Anwendungskonfiguration mit Apache Tamaya

Nahezu jede Anwendung muss irgendwie konfiguriert werden – seien es Namen, die statt im Code fest eingebaut zu werden, aus einem File gelesen werden sollen, seien es Berechnungsparameter oder URLs. Java (EE) bietet dazu bislang keinen Standard an, so dass jeder sich „sein eigenes Süppchen kochen“ muss.

Nun zeigt sich ein Silberstreif am Horizont in Form eines API zur Konfiguration von Anwendungen, das auf der diesjährigen Java One als Bestandteil von Java EE 8 angekündigt wurde und das Ideen aus dem entsprechenden Teil von Apache DeltaSpike und von Apache Tamaya übernehmen soll. Letzteres soll im Folgenden kurz beschrieben werden.

Apache Tamaya (tamaya.incubator.apache.org) befindet sich derzeit noch in einem sehr frühen Stadium, bedient sich aber bewährter Ideen aus Apache DeltaSpike Configuration und ist somit durchaus in Grenzen bereits einsetzbar.

Apache Tamaya ist modular aufgebaut. Der Core-Anteil wird immer benötigt. Darüber hinaus gibt es diverse Extensions wie bspw. zur Bereitstellung von Konfigurationswerten per CDI Injection. Für Maven-Projekte sind dies die folgenden Dependencies:

<dependency>
  <groupId>org.apache.tamaya</groupId>
  <artifactId>tamaya-core</artifactId>
  <version>${version.tamaya}</version>
</dependency>
<dependency>
  <groupId>org.apache.tamaya.ext</groupId>
  <artifactId>tamaya-cdi</artifactId>
  <version>${version.tamaya}</version>
</dependency>

Derzeit (Dez. 2016) ist die aktuelle Version 0.2-incubating.

Konfigurationswerte können mit einem einfachen API abgeholt werden:

String javaVendor 
  = ConfigurationProvider.getConfiguration()
                         .getOrDefault("java.vendor", "unknown");

ConfigurationProvider.getConfiguration() liefert dabei das Einstiegsobjekt vom Typ Configuration, das neben der oben genutzten Methode getOrDefault auch solche anbietet, die den Wert in einen anderen Typ als String gewandelt liefern.

In CDI Beans kann zudem per Injektion auf die Werte zugegriffen werden:

@Inject
@Config(defaultValue = "unknown")
String companyName;

@Inject
@Config
int answerToLifeUniverseAndEverything;

@Inject
@Config("java.version")
String javaVersion;

Apache Tamaya holt die Werte per Default aus System Properties, Environment Entries und der Datei META-INF/javaconfiguration.properties im Classpath. Es können weitere Property Sources registriert werden und auch die Suchreihenfolge manipuliert werden.

Weitergehende Informationen finden sich auf der Homepage des Projektes (tamaya.incubator.apache.org). Aufgrund des aktuellen Projektstands ist aber noch viel im Fluss.

Ein Demo-Projekt zum Anschauen und Ausprobieren gibt es hier: github.com/GEDOPLAN/config-demo.

Advertisements

Java EE mit Java 8 verschönern!

J2EE war recht komplex und unübersichtlich, was viele durchaus zu Recht zu anderen Plattformen getrieben hat. Seit Java EE 5/6/7 ist das Thema aber deutlich verbessert: Der Fokus liegt nun eindeutig auf der Unterstützung der Entwickler und nicht mehr, wie zuvor, auf der für den Betrieb notwendigen Technik.

Durch Java 8 läßt sich nun noch eine weitere Verschönerung erreichen. Damit werden Java-EE-Anwendungen deutlich strukturierter!

Das folgende kleine Java-8-Programm tut den Trick:

package de.gedoplan.beantrial;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.stream.Collectors;

public class SourceCleaner
{

  public static void main(String[] args) throws IOException
  {
    for (String filename : args)
    {
      Files
        .lines(Paths.get(filename))
        .flatMapToInt(line -> line.codePoints())
        .mapToObj(i -> Character.valueOf((char) i))
        .collect(Collectors.groupingBy(x -> x, Collectors.summingInt(x -> 1)))
        .entrySet()
        .stream()
        .map(e -> new String(new char[e.getValue()]).replace('\0', e.getKey()))
        .forEach(System.out::println);
    }
  }
}

Aus einer unübersichtlichen Quelle wie der folgenden

package de.gedoplan.seminar.cdi.demo.intercept.interceptor;

import java.io.Serializable;

import javax.inject.Inject;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
import javax.transaction.Status;
import javax.transaction.SystemException;
import javax.transaction.UserTransaction;

import org.apache.commons.logging.Log;

/**
 * Interceptor-Implementierung zu {@link TransactionRequired}.
 * 
 * @author dw
 */
@TransactionRequired
@Interceptor
public class TransactionRequiredInterceptor implements Serializable
{
  private static final long serialVersionUID = 1L;

  @Inject
  Log                       logger;

  @Inject
  UserTransaction           userTransaction;

  /**
   * Interceptor-Arbeitsmethode.
   * 
   * @param invocationContext InvocationContext
   * @return Returnwert
   * @throws Exception bei Fehlern
   */
  @AroundInvoke
  public Object manageTransaction(InvocationContext invocationContext) throws Exception
  {
    // Falls schon eine TX aktiv, Methode direkt aufrufen
    if (isTransactionActive())
    {
      return invocationContext.proceed();
    }

    // TX beginnen
    if (this.logger.isDebugEnabled())
    {
      this.logger.debug("Begin tx");
    }
    this.userTransaction.begin();

    try
    {
      // Methode aufrufen
      Object result = invocationContext.proceed();

      // TX committen
      if (this.logger.isDebugEnabled())
      {
        this.logger.debug("Commit tx");
      }
      this.userTransaction.commit();

      return result;
    }
    catch (Exception e) // CHECKSTYLE:IGNORE Allgemeine Exception ist hier OK
    {
      // TX zurückrollen
      if (this.logger.isDebugEnabled())
      {
        this.logger.debug("Rollback tx");
      }
      try
      {
        this.userTransaction.rollback();
      }
      catch (Throwable ignore)
      {
      }

      throw e;
    }

  }

  // Ist die TX aktiv?
  private boolean isTransactionActive() throws SystemException
  {
    return this.userTransaction.getStatus() == Status.STATUS_ACTIVE;
  }
}

wird die folgende, übersichliche und auch kürzere Form:

                                                                                                                                                                                                                                                                                                                                                                                                        
""""""
(((((((((((((((((((((
)))))))))))))))))))))
**************
,
--
...................................................
//////////////////
1
:
;;;;;;;;;;;;;;;;;;;;;;;;
====
?
@@@@@@@@@@
AAAAAAAA
B
CCCCCCCCCCC
DDDD
EEEEEEEEEEEEE
FF
G
H
IIIIIIIIIIIIIIIIII
KK
LLLL
MM
N
OOOO
RRRRRR
SSSSSSSSSS
TTTTTTTTTTTTTTTTTTTTTTT
UUUU
VV
XXXXX
Y
_
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
bbbbbbbbbbbbbbbbbbbbbbb
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
ddddddddddddddddddddddd
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
fffffffff
ggggggggggggggggggggggggggggggggggggg
hhhhhhhhhhhhhhhhhhhhhhhhh
iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
jjjjjjjjjjjjjj
kkkkkkkkkk
llllllllllllllllllllllllllllllllllllllll
mmmmmmmmmmmmmmmmmmmmmmmmmmmmm
nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
ppppppppppppppppppppppppppppppppppppp
qqq
rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr
sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt
uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
vvvvvvvvvvvvvvvvvvvvvvv
wwwwwww
xxxxxxxxxxxxxxxxxxxxxxx
yyyy
zzzz
{{{{{{{{{{{{
ü
}}}}}}}}}}}}

Probieren Sie’s aus. Es funktioniert übrigens nicht nur für Java-Quellen, sondern auch für JavaScript, HTML, ja sogar für C#!