Friday, July 28, 2017

Atualizando a variável JAVA_HOME no Linux

JAVA_HOME é uma variável de ambiente que aponta um diretório JDK no seu sistema. Essa variável é utilizada como referência por vários aplicativos que usam o java para rodar. Se ela não existir ou estiver incorretamente configurada, muitos aplicativos podem não executar.

O arquivo home/.bashr contém o script the execução além de vários parâmetros para iniciar o shell bash, que é a versão mais comum em Linux para terminais de linhas de comando. Para atualizar a JAVA_HOME anexamos o camando export no final do arquivo .bashr junto com o novo valor da variável.

Suponha que você baixou a última versão do JDK, que hoje é jdk1.8.0_141, no diretório:

/usr/lib/jvm/jdk1.8.0_141/

Utilizando o editor de texto vi, abra o arquivo .bashr
vi .bashr
Adicione no final do arquivo os camandos:

export JAVA_HOME=/usr/lib/jvm/jdk1.8.0_141/
export PATH=$JAVA_HOME/bin:$PATH

No final do arquivo adicionamos o novo valor de JAVA_HOME e exportamos para o PATH
Variáveis de ambiente e de shell são definidas através do comando export. A última linha adiciona a variável JAVA_HOME na variável PATH, a qual mapeia todos os comandos reconhecidos pelo terminal shell bash.

Observação: o editor de texto vi funciona em dois modos, comando e inserção, caso você tenha alguma dificuldade, dê uma olhada aqui. Ou você também pode utilizar outro editor de texto, como o nano por exemplo.

Salve e feche o arquivo. Efetive as mudanças que você acabou de realizar no arquivo .bash utilizando o camando source:
source ~/.bashrc
Pronto! Agora imprima o valor de JAVA_HOME. A saída deve ser semelhante à do comando  java -version:
$ echo $JAVA_HOME
/usr/lib/jvm/jdk1.8.0_141
$ java -version
java version "1.8.0_141"
Java(TM) SE Runtime Environment (build 1.8.0_141-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.141-b15, mixed mode)
Seu java está atualizado.

Wednesday, July 5, 2017

Adding Commands to Linux PATH

If you know in which directory the command you want execute is, just type the path until .sh file and run it. This might be boring if the path is too long though. A more effective way is creating a script containing the whole command and add it to the environment variable PATH.

In order to know which directories are mapped by the PATH, run:
echo $PATH
A possible output is this:
/home/rafael/bin:/home/rafael/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/usr/lib/jvm/java-8-oracle/bin:/usr/lib/jvm/java-8 oracle/db/bin:/usr/lib/jvm/java-8-oracle/jre/bin
The mapped directories are split by two points. Some directories are mapped by default. As you can see ~/bin (/home/rafael/bin) is one of these. This means that if we add some scripts in ~/bin, we will be able to run those scripts from anywhere by just prompting the file script name.

Example: Running Wildfly10 server through the PATH

Assuming your Wildfly server is located at /usr/share/wildfly-10.1.0.Final, let's add to PATH two commands, one to start the server and other to start the server client interface whose full path is /usr/share/wildfly-10.1.0.Final/bin/jboss-cli.sh.

We are just going to create one file called wildfly10 (touch wildfly10) to start the server and other called wildfly_cli (touch wildfly_cli) to run the client, each one containing the respective scripts (echo "..."). After that we give permission (chmod 755...) to make these files executable and that's all.

Starting from your home directory, type:
cd bin
touch wildfly10
echo "sudo /usr/share/wildfly-10.1.0.Final/bin/standalone.sh" > wildfly10
chmod 755 wildfly10
touch wildfly10_cli
echo "sudo /usr/share/wildfly-10.1.0.Final/bin/jboss-cli.sh" > wildfly10_cli
chmod 755 wildfly10_cli
Ready! Wildfly command is on your PATH. Let's try it:

First we start the server by prompting wildfly10

And now running the client server:

Prompting wildfly_cli from anywhere we start the client

And accessing server http port:

localhost:9990

You can add any commands you want to the PATH!


Tuesday, July 4, 2017

Casos de Mapeamento de Coleções no JPA

Aplicações corporativas são essencialmente definidas por sua necessidade de colher, tranformar e exibir uma quantidade enorme de informações. Java Persistence API (JPA) é o framework padrão de aplicações java para fazer a ponte entre o domínio orientado a objetos e o modelo relacional de banco de dados.

Coleções do tipo Collection, List, Set, Map são umas das estruturas de dados mais utilizadas e o JPA permite seu mapeamento para o modelo relacional  de forma simples e eficiente. Você só precisa utilizar as anotações adequadas e não se preocupar como as coleções estão sendo representadas no banco de dados! Vejamos os casos mais comuns de mapeamento de coleções, sejam as coleções classes de entidade, classes embutidas ou tipos básicos:

  • Multiplicidade simples entre uma classe de entidade e classes não-entidade (classes embutidadas)
Exemplo: Uma empresa pode ter muitos endereços (Endereço aqui é uma classe embutida):
@Embeddable
class Endereco{}

@Entity
class Empresa{

   @ElementCollection
   Set<Endereco> enderecos; 

//para classes embutidas, utilize @ElementCollection.
}
Opcionalmente você pode especificar como o JPA deve gerar a tabela de coleções no banco de dados fornecendo alguns parâmetros:
@Entity
class Empresa{

   @Id int idEmpresa;

   @ElementCollection
   @CollectionTable(name="logradouro", joinColumns=@JoinColumn(name="emp_id"))
   @AttributeOverride(name="address", column=@Column(name="o_nome_q_vc_quiser"))
   Collection<Endereco> enderecos;
}
No exemplo anterior, para representar a coleção de endereços da empresa, dissemos para o JPA criar uma tabela chamada logradouro. @JoinColumn representa a chave estrangeira.

Usar a anotação @ElementCollection é o mínimo que você precisa fazer para mapear a maioria dos tipos de coleções. Nos próximos exemplos vamos explorar coleções mais sofisticadas utilizando índices.


Multiplicidade indexada (pares chave/valor)


Pares chave/valor são representados pela interface Map. Coleções desse tipo são muito comuns e são utilizadas em praticamente todas as aplicações. O JPA é bastante flexível com tipos Map. As entidades ou classes embutidas podem representar tanto a chave quanto o valor, ou ainda chave e valor podem ser tipos primitivos.

1 Chave e Valor são tipos primitivos


Exemplo: Um funcionário pode ter vários números de telefone e cada número é de um tipo (comercial, trabalho, casa, etc.):

Essencialmente você só precisa da usar a anotação @ElementCollection para resolver seu problema. Todas as outras são opcionais.
@Entity
public class Funcionario{

   @Id private int id;

   @ElementCollection
   @CollectionTable(name="funcionario_telefone") //opcional, define o nome da tabela no banco
   @MapKeyColumn(name="tipo_telefone") ///opcional indica qual coluna armazena achave
   @Column(name="numero") //nome da coluna que armazena o valor
   private Map<String, String> telefones;
   //...
}
2 A chave do Map pode ser uma enum ou uma data
Constantes enumeradas dão mais consistência e legibilidade ao código. Como no exemplo anterior, mas ao invés de usarmos um tipo básico como chave, usamos uma enum. Novamente a única anotação obrigatória é @ElementCollection, mas podemos definir como o valor da enumeration será armazenado no banco de dados, se sob a forma literal ou numérica, assim precisamos utilizar a anotação @MapKeyEnumerated
public enum TipoTelefone {HOME, MOBILE, WORK}

@Entity
public class Funcionario{

   @Id private int id;

   @ElementCollection
   @CollectionTable(name="funcionario_telefone") //opcional, define o nome da tabela no banco
   @MapKeyEnumerated(EnumType.STRING)
   @MapKeyColumn(name="tipo_telefone") ///opcional indica qual coluna armazena a chave
   @Column(name="numero") //nome da coluna que armazena o valor
   private Map<TipoTelefone, String> telefones;
   //...   
}
Caso quisessemos usar como chave o tipo java.util.Date, poderíamos usar a anotação @MapKeyTemporal ao invés de @MapKeyEnumerated.

3 Chave é um tipo básico e valor é uma entidade
Exemplo: Um departamento tem vários cubículos cada qual com um funcionário.
A modelagem tradicional um departamento tem muitos funcionários ainda não atenderia eficazmente esse cenário. O software precisa indexar cubículo e funcionário.
@Entity
public class Departamento{

   @Id private int id;

   @ManyToMany
   @JoinTable(name="DEPT_EMP", joinColumns=@JoinColumn(name="DEPT_ID"),
                    inverseJoinColumn=@JoinColumn(name="EMP_ID"))
                    @MapKeyColumn(name="CUB_ID")
   private Map<String, Funcionario> funcionarioPorCubiculo;
}
4 Chave é o ID da própria entidade que representa o valor do Map
É comum e intuitivo indexar a chave do map pelo ID da entidade. No exemplo anterior o poderíamos usar algum atributo do funcionário como identificador do cubículo ao invés do próprio nome atribuído pelo departamento.
@Entity
public class Departamento{
   @Id private int id;
   @OneToMany(mappedBy="departamento")
   @MapKey(name="id")
                private Map funcionarios;
}
5 Chave é uma entidade e valor é um tipo básico
Exemplo: Atribuir a senioridade de cada funcionário no departamento em um contexto onde o funcionário pode atuar em vários departamentos e a senioridade podendo variar, uma vez que ela é determinada em função do departamento (um funcionário pode ser pleno no setor de desenvolvimento e junior no departamento de infraestrutura...).
@Entity
public class Department{

   @Id private int id;

   @ElementCollectionn
   @CollectionTable(name="emp_senioridade")
   @MapKeyJoinColumn(name="emp_id")
   @Column(name="senioridade")
   private Map<Employee, Integer> seniorites;
   // ...
}