Conhecendo a JSR-382: Configuration API 1.0

config

Neste post vamos conhecer um pouco sobre a nova especificação de configuração para Jakarta EE .

Esta especificação define uma maneira fácil e flexível  para configuração de aplicações, alem de definir maneira de estender o mecanismo de configuração por meio de um SPI (Service Provider Interface) de modo portátil .

A JSR-382 é baseada na inovação do projeto Eclipse Microprofile Config que é realizado por vários colaboradores, tanto por empresas, comunidades como a SouJava e individuais, como o objetivo de identificar uma solução viável minima para dados de configuração de aplicações e micro serviços com a esperança de padronizar via JCP .

Esta JSR foi submetida por todos os membros da comunidade Eclipse MicroProfile .

Introdução a JSR-382 ( JavaConfig )

A maioria das aplicações precisam ser configuradas com base em um ambiente em execução . Esse podem ser os números de portas, endpoint das extremidade Rest ou recursos inteiros que precisam ser ligados e desligados dependendo da instalação.

Tudo isso deve ser possível  sem a necessidade de re-empacotar toda a aplicação a cada mudança, alem de levar em consideração as arquiteturas de microserviços e ambientes de contêiners atuais.

A especificação da APi Configuração ou JavaConfig fornece esse objetivo, agregando a configuração de muitos ConfigSources diferentes e apresentando uma única visão mesclada para o usuário, ou seja uma instancia de Config. 

Isso permite um agrupamento  padrão de configuração dentro da aplicação, alem de permite substituir os padrões de fora, por exemplo : via uma variável de ambiente, uma propriedade do sistema Java ou por meio de um contêiner como Docker ou Kubernetes .

JavaConfig também permite implementar e registrar fontes de configuração(ConfigSources)  próprias de maneira portátil como por exemplo : ler valores de configuração de um banco de dados compartilhado em um cluster de aplicações.

O mecanismo principal do JavaConfig é puramente baseado em String. O Type-Safety é intencionalmente fornecido em cima disso, usando apenas os conversores adequados antes de entregar o valor para o chamador.

A chave de configuração pode usar blocos separados por pontos(.) para evitar conflitos de nome. Isso é semelhante aos nomes dos pacotes em Java :


br.org.soujava.url.site=http://soujava.org.br

aqui o exemplo esta na sintaxe do arquivo de propriedade do Java, o conteúdo real poderia também ser lido de um banco de dados ou outros meios.

aqui uma lista de projetos que inspiram diretamente a criação dessa proposta e atuaram como base para essa API como :

E a abordagem de desses foi mesclada no MicroProfiel-Config  e agora serve como ponto de partida para a JSR-382.

Gerando o Build  e Criando o Projeto

Atualmente a JavaConfig ainda não tem uma RI (Implementação de Referencia) oficial, conforme pode ser visto na seguinte mensagem de um dos lideres da SPEC Mark Struberg para mim :

giiter

como eu não sei qual é a implementação da IBM e da Red Hat, a gente vai usar o Apache Geronimo Config .

outra coisa é que tanto a JavaConfig quanto o Geronimo-Config ainda não estão disponíveis no Maven Central, então a gente vai gerar esse dois localmente , segue os seguinte passos :

1 – Faça o fork  e clone da JavaConfig :  https://github.com/eclipse/ConfigJSR e do Geronimo  https://github.com/apache/geronimo-config (branch ConfigJSR)

2 – Faça o build da JavaConfig e do Geronimo-Config(branch ConfigJSR) com o seguinte comando :

JavaConfig :


mvn clean install -DskipTests

Geronimo-Config :

git checkout ConfigJSR
mvn clean install -DskipTests

feito isso crie um novo projeto Maven com as seguintes dependências :

aqui a JsonB é somente para exibir uma saída bonita, não é obrigatório para a SPEC funcionar.

Exemplos de uso de configuração

Uma aplicação pode obter  sua configuração via programaticamente por meio do ConfigProvider  e no CDI  com beans habilitados para serem injetados via @Inject Config , com isso uma aplicação pode acessar seus valores configurados por meio dessa instancia de Config .

Um Config consiste nas informações coletadas dos javax.config.spi.ConfigSource registrados . Esses ConfiSource são classificados de acordo com o seu ordinal. Dessa forma é possível sobrescrever a configuração com menor importância .

Por default, existem 3 ConfigSources padrão :

 1 – System.getProperties() (ordinal=400)

2 – System.getenv() (ordinal=300)

3 – todos os arquivos META-INF/javaconfig.properties (ordinal=100, configurado separadamente através de uma propriedade config_ordinal dentro de cada arquivo)

Simples exemplo programatico

para o primeiro exemplo vamos utilizar via programaticamente, para isso criar um  arquivo properties com o seguinte nome : javaconfig.properties na pasta src/main/resources/META-INF com o seguinte conteúdo de chave/valor :


org.jug.nome=SouJava-Rio
org.jug.membros.quant=709
org.jug.reuniao.mes=1
org.jug.site.url=https://soujava-rio.github.io/

agora cria uma classe com método main e vamos chamar esse valores :


package br.org.soujava.rio.javaconfig;

import java.util.List;

import javax.config.Config;
import javax.config.ConfigProvider;
import javax.json.bind.JsonbBuilder;
import javax.json.bind.JsonbConfig;

/**
* @author Daniel Dias
* github:Daniel-Dos
* daniel.dias@soujava.org.br
* twitter:@danieldiasjava
*/
public class JavaConfiguration {
public static void main(String[] args) {

   Config config = ConfigProvider.getConfig();

   var jsonbConfig = new JsonbConfig().withFormatting(true);
   var jsonB = JsonbBuilder.create(jsonbConfig);

   var nomeJug = config.getValue("org.jug.nome", String.class);
   var siteURL = config.getValue("org.jug.site.url", String.class);
   var reuniaoMes = config.getValue("org.jug.reuniao.mes", Integer.class);
   var quanMembro = config.getValue("org.jug.membros.quant", Integer.class);

   var JUGConfig = List.of(nomeJug, siteURL, reuniaoMes,quanMembro);

   var output = jsonB.toJson(JUGConfig);

   System.out.println(output);
   }
 }

Aqui para usar a JavaConfig em modo programático, temos que usar a classe ConfigProvider  que é o ponto central de acesso a configuração . Isso permite acesso a diferentes configurações (representada por uma instancia de Config) na aplicação em que é usado.

Além disso, internamente o ConfigProvider delega até o ConfigProviderResolver, que contém mais funcionalidades de baixo nivel.

Existem 4 maneiras diferentes de criar uma instância do Config:

1 – Em um componente gerenciado pelo CDI atraves do @Inject para acesso a atual configuração da aplicação.

2 – Pelo método de fabrica ConfigProvider.getConfig()  para criar um objeto Config com base no ConfigSource pego automaticamente da aplicação identificada pelo ClassLoader.

3 – Pelo método de fabrica ConfigProvider.getConfig(ClassLoader forClassLoader) este pode ser usado se uma thread do ClassLoader não representar uma camada correta. ex: se necessitamos de um Config para um EAR compartilhado.

4 – e por meio do método de fabrica ConfigProviderResolver.getConfig.instance().getBuilder()  para criar um objeto ConfigBuilder .  O mesmo não possui um ConfigSource, mais apenas os conversores padrão incluídos.

O ConfigBuilder, pode ser preenchido manualmente via ConfigBuilder#withSources  que por padrão. a instancia de Config não será compartilhada pelo ConfigProvider.

Esse método se destina a ser usado se um IoC ou qualquer outroa fabrica puder ser usada para dar acesso a configuração compatilhada criada manualmente.

a saida é um doc json com o valores vindo do javaconfig.properties: 

saida2

agora veremos o mesmo exemplo, porem usando CDI .

Simples exemplo com CDI

para isso, adicione o seguinte arquivo beans.xml na pasta src/main/resources/ com o seguinte conteúdo :

e vamos alterar a nossa classe com o seguinte conteúdo :


package br.org.soujava.rio.javaconfig;

import java.util.List;

import javax.config.inject.ConfigProperty;
import javax.enterprise.event.Observes;
import javax.inject.Inject;
import javax.json.bind.JsonbBuilder;
import javax.json.bind.JsonbConfig;

import org.jboss.weld.environment.se.events.ContainerInitialized;

/**
 * @author Daniel Dias
 * github:Daniel-Dos
 * daniel.dias@soujava.org.br
 * twitter:@danieldiasjava
 */

public class JavaConfiguration {

	@Inject
	@ConfigProperty(name="org.jug.nome", defaultValue="SouJava")
	private String nomeJug;

	@Inject
	@ConfigProperty(name="org.jug.site.url", defaultValue="http://soujava.or.br")
	private String siteURL;

	@Inject
	@ConfigProperty(name="org.jug.reuniao.mes", defaultValue="0")
	private int reuniaoMes;

	@Inject
	@ConfigProperty(name="org.jug.membros.quant", defaultValue="8")
	private int quanMembros;

	public void main(@Observes ContainerInitialized event) {

		var jsonbConfig = new JsonbConfig().withFormatting(true);
		var jsonB = JsonbBuilder.create(jsonbConfig);

		var JugConfig = List.of(nomeJug, siteURL, reuniaoMes, quanMembros);

		System.out.println(jsonB.toJson(JugConfig));
	}
}

 

aqui a chave da propriedade config (@ConfigProperty) usada para procurar o valor da configuração.

já o valor defautl  é usado se o valor da propriedade não exista. Se o tipo de destino não for uma String um javax.config.spi.Converter apropriado será aplicado. Isso significa que qualquer String de valor padão deve seguir as regras de formatação dos conversores cadastrados.

para executar use a seguinte chamada de classe Main da CDI : org.jboss.weld.environment.se.StartMain, se estiver usando o Eclipse IDE, segue a imagem :

eclipse

a saida é um doc json com o valores vindo do javaconfig.properties: 

cdi

 

Conversor

Para fornecer uma configuração Type Safe, precisamos converter as String configuradas para um formato apropriado, isso a JavaConfig fornecer o um conversor para os seguinte tipos :

  • boolean e Boolean. valores para true (insensitivo a maiúsculas) “true”, “1”, “YES”, “Y”, “ON”. Qualquer outro valor será interpresado como falso.
  • int e Integer
  • long e Long
  • float e Float, o “.” é usado para separar os dígitos fracionários.
  • double e Double, o “.” é usado para separar os dígitos fracionários.
  • URL

Além disso podemos adicionar conversores customizados bastando implementar a interface genérica  javax.config.spi.Converter  e registrar a sua implementação em um arquivo na pasta /META-INF/services/javax.config.spi.Converter com o nome completo da classe customizada.

ConfigAccessor

A API do ConfigAccessor é destinada a valores de configuração digitados e controle preciso sobre a resolução .

O uso mais simples do ConfigAccessor é a resolução de uma propriedade String, que é equivalente a chamada do Config.getValue(propertityKey, String.class ) conforme o seguinte exemplo :


@Inject

private Config config

String jugNome = config.access("org.jug.nome").getValue();

 

Além disso, o ConfigAccessor também permite um controle muito mais complexo sobre o acesso a valores configurados, como o exemplo extraido da spec :

 

Bem isso é tudo, espero que os leitores tenham gostado de conhecer um pouco sobre a JSR-382 .

código de exemplo no  github – JSR-382-JavaConfig .

Referencias

Anúncios

Eclipse Che sua IDE na nuvem.

wl-eclipse-che

Neste post veremos como podemos utilizar a IDE Cloud Eclipse Che para para desenvolver nossas aplicações Java .

Introdução ao Eclipse Che

Eclipse Che é um servidor de WorkSpace baseado em Java de código aberto uma IDE em nuvem que fornece uma plataforma de desenvolvimento remoto para fins de multiusuários . O Servidor de WorkSpace vem com um serviço de RestFul e oferece alta flexibilidade, além de conter um SDK que pode ser usado para criar plugins para linguagens, ferramente ou frameworks.

A principal diferença entre o Eclipse Che e o Eclise IDE padrão é a capacidade de criar contêiner Docker para executar os aplicativos.

O eclipse Che suporta as seguintes Linguagens e Frameworks :

  • C++ , Java, JavaScript, PHP, Python, Ruby, SQL
  • .Net 2.0, AngularJS, Docker, OpenShift, Yeoman
  • Ant, Bower, Grunt, Gulp Maven, Npm
  • Git, Orion, SSH, SubVersion

Após a carga inicial, a IDE fornece uma interface de usuário dinâmica, incluindo componentes conhecidos como assistentes, editores, barras de ferramentas e muito mais. O usuário tem a oportunidade de criar espaços de trabalho, projetos, ambientes, máquinas e muitos outros módulos que são necessários para criar um projeto a partir do zero.

A comunicação entre a interface do usuário e o servidor é feita usando as APIs RESTful que interagem com o chamado Master de WorkSpace .

Um espaço de trabalho pode incluir zero ou mais projetos e deve, pelo menos, incluir um ambiente, que ele próprio contém pelo menos uma máquina.

Uma máquina é um tempo de execução que possui o software necessário. Se o usuário adicionar, por exemplo, um projeto que usa o Apache Maven, o Workspace Master instala o Maven em qualquer máquina no espaço de trabalho para garantir que o projeto possa ser executado em cada máquina.

Che vem com algumas pilhas de tecnologia predefinidas para configurar rapidamente uma nova máquina. Para garantir alta flexibilidade e extensibilidade, o usuário também pode definir pilhas de tecnologia personalizadas que podem ser usadas para configurar novas máquinas. Por padrão o Eclipse Che é executado em um servidor Apache Tomcat utilizando a porta 8080.

O leitor pode ler mais sobre o assunto nos seguintes links :

Bem feita essa rápida introdução sobre o Eclipse Che, vamos partir para a parte legal, a prática .

Requisitos

  • Docker 17+  instalado em sua maquina -> Download .

Feito a instalação do Docker , podemos seguir com a instalação do Eclipse Che .

Instalando o Eclipse Che

Para instalar execute o seguinte comando :


docker run -it --rm
-v /var/run/docker.sock:/var/run/docker.sock
-v seuCaminho:/data:/data
eclipse/che:6.1.1 start

A  apos esse comando, ele ira baixar as imagens necessárias para sua inicialização e a saída sera semelhante a essa :

start

Antes de fazemos qualquer coisa, iremos modificar algumas coisa em sua configuração, como habilitar o uso externo do Maven local, utilizar o Eclipse Che em modo OFFLINE e alterar o modo de como o Eclipse Che faz o Pull das imagens .

Primeiro de tudo, pare a execução do container e remova o mesmo com o seguinte comando :

docker stop che && docker rm che

apos isso vamos alterar o seguinte arquivo  “che.env” que fica localizado da pasta Data na hora de monta o volume, no meu caso fica em “/home/daniel/eclipseChe/data“, abra o arquivo dando acesso para alteração ao mesmo e procure e descomente os seguintes trechos :

  • CHE_DOCKER_ALWAYS__PULL__IMAGE=false : Se TRUE, o Che sempre ira fazer PULL de uma imagem do registro, mesmo que seja armazenada em Cache. Se FALSE, o Docker so faz pull se a imagem não existir localmente.
  • CHE_WORKSPACE_VOLUME= : Uma lista separada por “;” para montagem de volumes. Che ira montar o volume destas pasta host em cada workspace. Esse é uma maneira de permitir que você forneça acesso compartilhado em vários workspace . No meu caso ficaria assim :

CHE_WORKSPACE_VOLUME=/opt/apache-maven-3.5.2/repo:/home/user/.m2/repository;

/data/db:/data/db;

/home/daniel/oracle/postgre/data/:/var/lib/postgresql/data;

feita essas mudanças salve o arquivo, vamos partir para o modo OFFLINE .

A instalação offline baixa a CLI, as principais imagens do sistema e todas as imagens de pilha enquanto você está dentro de uma DMZ de rede com acesso DockerHub. Você pode então mover esses arquivos para um ambiente seguro e começar o Che.

1-  Salvando as imagens :

Enquanto estiver conectado a internet o Che ira fazer o download das imagens docker com o seguinte comando :


docker run -it --rm
-v /var/run/docker.sock:/var/run/docker.sock
-v seuCaminho:/data:/data
eclipse/che:6.1.1 offline

a saída será semelhante a essa :

offline

no meu caso ele só fez o download do “docker_compose:1.10.1.tar”, pois já tenho as outras imagem baixadas anteriormente.

A CLI irá baixar imagens e salvá-las em /backup/*.tar com cada imagem salva como seu próprio arquivo. Você pode salvar esses arquivos em uma localização diferente por volume, montando uma pasta local para: / data / backup. A tag de versão da imagem CLI Docker será usada para determinar quais versões de imagens dependentes para download. Há cerca de 1GB de dados que serão salvos.

Você também pode fazer o download das Stacks separadamente com o seguinte comando :


docker run -it --rm
-v /var/run/docker.sock:/var/run/docker.sock
-v seuCaminho:/data:/data
eclipse/che:6.1.1 offline --list

ao executar ira mostrar uma lista de imagens conforme a imagem :
stacks
para fazer o download de uma stack especifica executamos o seguinte comando :
docker run -it --rm
-v /var/run/docker.sock:/var/run/docker.sock
-v seuCaminho:/data:/data
eclipse/che:6.1.1 offline --image:nomeDaImagem

feito isso podemos iniciar nosso Eclipse Che em modo OFFLINE e iniciar nosso Hello-World .

Para iniciar o Eclipse Che execute o seguinte comando :


docker run -it --rm
-v /var/run/docker.sock:/var/run/docker.sock
-v seuCaminho:/data:/data eclipse/che:6.1.1 start --offline

a saída sera semelhante a essa com todos os tar’s carregados :

offiline2

agora basta abri o seu navegador passando o endereço informado na tela, que no meu caso é http://192.168.1.100:8090 e a seguinte tela ira abrir :

workspace

No meu caso meu “Dashboard” contem um workspace criado com 2 projetos nele. Vamos criar um do zero agora .

Criando o WorkSpace

Primeiramente clique em “Create Workspace “, isso ira abri a seguinte tela :

newWorkspacenewWorkspace2

Nesta tela é aonde criamos nosso workspace com algumas stack prontas uso .

Uma Stack é um modelo de configuração de workspace e algumas meta-informações como escopo, tags, componentes, descrição, nome e ID. As Stacks são usadas pelo Dashboard para facilitar a criação de workspace e bem como projetos de exemplo de filtro compatíveis com uma pilha escolhida.

As pilhas são exibidas no Painel do Usuário na página Criar uma área de trabalho. Você pode filtrá-los por tipo (single vs multi machine), scope (os exibidos por padrão vs outros), bem como procurar uma pilha por palavra-chave.

Para o primeiro exemplo iremos criar um projeto simples com uma Servlet, então fazemos o seguinte :

1 – De um nome para o WorkSpace.

2 – Escolha a Stack “Java” abaixo da Stack “Blank”

3 – Clique em “CREATE”

4 – ira apresentar uma popup com duas opções “Edit” ou “Open in IDE”, escolha a segunda opção .

Apos isso ira abri o editor conforme a imagem :

tela

Com a tela aberta vá no menu “Workspace” e clique em “Create Project” ou aperte “Alt + X” ira abir a seguinte tela :

newProject

escolha “Maven” e preencha o formulário de next e configure da seguinte forma :

newProject2

logo apos ira ter um projeto chamado Demo na workspace :

project

feito isso, abra o pom.xml e configure da seguinte forma :

 

depois clique com botão direito no seu projeto e vá no menu “Maven” ->”ReImport”, feito isso crie um “pacote” na pasta “java”  e em seguida cria uma classe Java com o seguinte conteúdo :


package br.org.soujava.rio.minhaServlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/minhaServlet")
public class MinhaServlet extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {

  PrintWriter out = response.getWriter();
  out.println("<h1>Minha Primeira Servlet com Eclipse CHE.</h1>");
  }
}

 

feito isso, vá na aba “Manage Commands” conforme a imagem :

manage

em seguida altere o “build ” com o seguinte comando  na parte “Command Line”, clique em “Save” e depois em “Run” :


mvn -f ${current.project.path} clean install
cp ${current.project.path}/target/*.war /home/user/tomcat8/webapps/

 

Apos isso, seu o projeto vai esta na pasta do Tomcat, agora para executar vamos criar um outro comando, para isso clique me “RUN” escolha a opção “Maven” e adicione o seguinte comando na “Command Line:


$TOMCAT_HOME/bin/./startup.sh

 

e em “Preview URL adicione o seguinte comando:


${server.tomcat8}/Demo-1.0-SNAPSHOT/minhaServlet

 

salve e execute e acesse o seguinte endereço : http://seuIp:32769/Demo-1.0-SNAPSHOT/minhaServlet :

servlet

parabéns conseguimos executar nossa primeira Servlet com Eclipse Che .

Os comandos são instruções de script que são injetadas na máquina do espaço de trabalho para execução. Os comandos são salvos no armazenamento de configuração do seu espaço de trabalho e fazem parte de qualquer exportação de espaço de trabalho.

para aprender mais sobre os comandos acesse o seguinte link.

A próxima demo faremos uso de múltipla maquinas onde iremos conectar nossas aplicações ao um Banco de Dados ou qualquer outra coisa. No nosso caso iremos usar um banco de dados.

Se o leitor percebeu la no começo quando estávamos criando uma workspace tinha varias stacks prontas para uso inclusive uma com Java + MySQL, porem o leitor pode não querer usar o MySQL, mas sim um PostGres ou até mesmo um NoSQL como MONGO DB.

Como podemos perceber não temos Stack para a mesma, então a gente ira criar uma stack personalizada se baseando na stack do MySQL.

Para isso vamos no menu “Stacks” conforme a imagem :

stacks2

nessa tela procure por “Java-MySQL” e clique em “Duplicate Stack” , logo em seguida clique na Stack duplicada e sera apresentada a seguinte tela :

newStarkc

agora vamos configurá-la para ele ser um Stack com banco NoSQL- MongoDB

1 – Altere o nome da stack para Java-Mongo ou qualquer outro nome.

2 – em “Machines” altere o “db”  :

2-1 – em “Source” adicionar : “mongo:latest” esse é o nome da imagem que o docker ira fazer o pull .

2-2 – em “Servers” alterar a porta para “27017” e mudar o reference também.

3 – vá em “Raw Configuration” e altere o trecho “content” para :


content": "services:\n db:\n image: 'mongo:latest'\n mem_limit: 1073741824\n dev-machine:\n image: eclipse/ubuntu_jdk8\n mem_limit: 2147483648\n depends_on:\n - db\n"

 

o arquivo final fica assim :

logo em seguida salve a nova Stack e vamos utilizá-la agora, para isso crie um novo workspace e selecione a nova stack criada.

La no começo eu ensinei a apontar a pasta local para se comunicar com a pasta do conteiner no trecho : CHE_WORKSPACE_VOLUME= , aonde eu aponta minha pasta “data/db” para a do conteiner.

Feito isso clique me Create e em “Open in IDE”, ele ira iniciar o Mongo e logo em seguida ira iniciar o a maquina de Dev :

mongo

agora iremos criar um projeto para utilizar essa nova stack, para isso va no menu “Workspace” e clique em “Import Project” > “Git” e adicione o seguinte endereço :  https://github.com/Adopt-a-JSR/MVC1.0.Ozark.git e clique em import, logo em seguida selecione “Maven” depois em “Next”, selecione “war” e depois clique em “Save” .

feito isso, abra o pom.xml para fazermos algumas modificações :

agora iremos modifica duas classes :

1 – DocumentCollectionProducer.java = alterar “localhost” para “db” que é o nome da maquina do mongodb

2- PersonController.java =  adicionar o import  org.mvcspec.ozark.engine.Viewable;”

essa mudança é necessária pois estamos usando uma versão nova da lib da Ozark.

feito isso, vamos criar um comando para fazer o build e executar a aplicação .

no “Command Line” adicione o seguinte trecho :


mvn clean package -f ${current.project.path}

&& cd ${current.project.path}/target

&& java -jar payara-micro.jar --deploy MVC1.0.Ozark.war

e em “Preview URL” adicionar o seguinte trecho :


${server.tomcat8}/${current.project.relpath}

e clique em “Run” e acesso  o endereço : http://192.168.1.100:32802/MVC1.0.Ozark/ :

payara

Bem isso é tudo, espero que os leitores tenham gostado de conhecer um pouco sobre Eclipse Che.

Continue seus estudos explorando mais essa IDE e criando novos Stacks personalizadas.

mais exemplos: https://www.eclipse.org/che/docs/tutorials/multi-machine/index.html

REFERÊNCIAS