Durante uma tentativa de configurar o banco de dados com a base de CEP dos Correios, obtive o seguinte erro: org.hibernate.HibernateException: Transaction was rolled back in a different thread!
Insistindo novamente, percebi que o erro ocorria sempre durante a inserção dos registros da tabela de logradouros, a qual possui mais de 1 milhão de registros.
Quando as transações são gerenciadas pelo container de aplicações (Container Managed Transactions), no meu caso o WildFly 12, elas têm um timeout defualt de 5 minutos. Ou seja, se você estiver realizando uma operação muito demorada, esse tempo pode se esgotar e o container vai lançar a excessão acima e dar um rollback na transação.
Para aumentar o timeout da transação, abra o console de administração do WildFly. A partir da aba Configurations, clique em Subsystems e depois Transactions. O Transaction Manager exibe uma série de opções de configuração para as transações, uma delas é o default timeout (em segundos). Clique em editar e coloque o valor que se adequa a sua demanda. Por exemplo, 900 segundos dividos por 60 equivalerão a transações com timeout de 15 minutos, ao invés de 5 (300 segundos).
Configuração de Transações no console de administração do WildFly 12
Um sistema de Dual-Booté um computador que possui dois ou mais sistemas operacionais instalados no mesmo HD, em partições diferentes, e dá a opção de carregar um ou outro durante a inicialização.
O Dual-Boot mais comum é criar duas partições e instalar uma versão do Windows em uma e uma do Linux na outra. Porém, dependendo de qual sistema operacional você instala primeiro, o Dual-Boot pode requerer mais algumas configurações para funcionar corretamente.
GRUB (GNU GRand Unified Bootloader) é o gerenciador de boot padrão em sistemas baseados em UNIX, como o Solaris e as distribuições Linux. Quando você liga o computador, o gerenciador de boot é o primeiro programa que roda, ele é responsável por carregar e tranferir o controle da máquina para o kernel do sistema operacional.
Quando você quer implementar um sistema Dual-Boot com Linux e Windows, e instala o Linux por último, o GRUB se encarrega de verificar se outras partições do HD possuem outros sistemas operacionais instalados, caso afirmativo, ao iniciar a máquina, ele exibe as opções disponíveis e espera o usuário selecionar qual sistema operacional ele quer carregar.
Porém se você instalar o Windows por último, ele sobreescreve o GRUB com o seu próprio gerenciador de boot, o Windows Boot Manager (BOOTMGR), o qual só é capaz de carregar versões do Windows, deixando outros sistemas Não-Microsoft incarregáveis (unloadable).
CENÁRIO: você tem um HD com duas partições. O Linux Mint 18.2 instalado em uma partição e o Windows 10 em outra. Como o Windows 10 foi instalado por último, o Linux não está mais carregando.
Implementando Dual-Boot após instalar o Windows 10 ao lado do Linux Mint 18.2
Basicamente você precisa reinstalar o GRUB, porém isso não poderá ser feito no Windows.
Crie uma imagem ISO da versão Linux que você usa em um pen drive. Você terá que dar um boot por esse dispositivo.
Após ligar a máquina, pressione F11 algumas vezes e depois F12 (essas teclas podem variar dependendo do fabricante), esse procedimento faz exibir o setup da BIOS, no qual você pode escolher por meio de qual drive a máquina deve iniciar (a aparência desse menu também pode variar por fabricante). Escolha a opção que corresponda ao drive USB, que contem a imagem da versão Linux que você utiliza.
Bios Menu
Após escolher o drive USB, o Linux será carregado. Agora você deve acessar a partição que contem o Linux e reinstalar o GRUB na pasta boot. Para isso, abra o shell e execute os seguintes comandos:
sudo fdisk -l para saber o nome da partição que contem o seu Linux
sudo mount /dev/<nomePartição> /mnt anexa à árvore de diretórios o sistema de arquivos da partição que contem o Linux
Execute os comandos como na imagem abaixo. Nela o nome da partição esquecida que contem o Linux é sda1 (você deve substituir pelo nome que aparecer na sua máquina), cujo tamanho é 619,6 GB:
Comandos para atualizar o GRUB
Repare que ao executar o comando sudo grub-install, aparece a mensagem de errofailed to get canonical path of 'auf'. Você pode ignorará-la.
Reinicie sua máquina. Dessa vez o GRUB dará a opção de escolher se você quer carregar o Windows ou o Linux. Caso o Linux carregue diretamente sem dar a opção de escolher o Windows, instale o Boot Repair.
Clientes de email são processos que acessam um serviço de email em algum servidor remoto. Esse modelo também é conhecido como modelo cliente-servidor. A essência desse modelo é a existência de um processo cliente e um processo servidor, geralmente em máquinas diferentes, mas nem sempre. No contexto deste post, o processo cliente é uma aplicação Java que acessa os serviços disponibilizados por um servidor de email remoto.
aplicação cliente de email
JavaMail API
JavaMail API é o framework Java para desenvolver sistemas que enviam, recebem e manipulam mensagens e qualquer tipo de conteudo através de um provedor de emails na internet. Sua especificação é definida pela JSR-919. O nucleo duro da API fica no pacote javax.mail e é parte integrante do Java Enterprise Edition (No Java Standard Edition é necessário incluir explicitamente a biblioteca para usá-la no seu projeto).
O JavaMail é uma API de alto-nível. Ou seja, ela é capaz de abstrair os componentes de um sistema de email, tais como mensagens, protocolos, pastas, repositório, etc, de maneira bastante intuitiva para o desenvolvedor, isso torna a inclusão de rotinas de mensageria na sua aplicação Java mais fácil e rápida.
Por exemplo, tome-se a classe final javax.mail.Session, que representa uma sessão de comunicação estabelecida entre a aplicação cliente e algum servidor remoto:
Os métodos são auto explicativos:
getInstance(Properties props, Authenticator auth): fabrica uma instância de javax.mail.Session devidamente autenticada com algum servidor de email sob as propriedades definidas no objeto java.util.Properties.
getStore(): retorna o repositório de email daquela conta no servidor de email. A partir de javax.mail.Store você pode acessar as pastas do repositório, como INBOX por exemplo, e manipular as mensagens contidas naquela pasta.
Toda API JavaMail segue esse padrão instuitivo e desacoplado . As principais classes do pacote javax.mail como Store, Folder, Message, Address são abstratas e a implementação concreta fica a cargo do provedor de email com o qual você está trabalhando.
Uma aplicação pode interagir com outra aplicação ou com um ser humano, neste último caso precisamos de uma interface gráfica amigável que possibilite ao usuário conversar com o sistema. JavaFX é a mais recente plataforma multimídia do Java Standard Edition, sucessora do javax.swing, que permite o desenvolvimento de interfaces gráficas avançadas para aplicações desktop e web que executam em uma variedade de dispositivos.
Neste post criamos uma aplicação cliente de email que utiliza:
API JavaMail para se conectar com o servidor de email remoto
JavaFX para criar a Interface Gráfica com o Usuário
Projeto Cliente-Servidor
Utilizando o eclipse, navegue pelos menus File/New/project. No assistente que abrir escolha Maven/Maven Project. No próximo assistente marque a opção Create a Simple Project. Next. Dê o nome ao seu projeto de JavaFxEmailClient e finalize.
Agora clique com o botão direito no diretório raiz de seu projeto e escolha MAVEN/Update Project. Pronto. Agora que nosso projeto está devidamente configurado podemos começar a criar as classes. O seguinte diagrama de classes define o design do nosso cliente de email:
ArquivoModel.java
Como nosso sistema cliente poderá enviar mensagens com anexos, a classe ArquivoModel representa um Wrapper do arquivo real. O padrão Wrapper serve para encapsular funcionalidades e criar um nível adicional de abstração:
package main;
//Classe Wrapper para trabalhar com um arquivo anexado
public class ArquivoModel {
private String nomeArquivo;
private byte[] conteudo;
private String mimeType;
public ArquivoModel(String nomeArquivo, byte[] conteudo, String mimeType) {
super();
this.nomeArquivo = nomeArquivo;
this.conteudo = conteudo;
this.mimeType = mimeType;
}
//getters & seters omitidos...
}
JanelaEnviar.java
A classe JanelaEnviar extende o container javafx.scene.layout.GridPane. Ela agrega todos os controles visuais que fazem a interface gráfica com o usuário e captura os eventos disparados pelo usuário:
package main;
//IMPORTS OMITIDOS...
//interface gráfica com o usuário GUI
public class JanelaEnviar extends GridPane {
//controles da GUI
TextField txtHostServer;
TextField txtPara;
TextField txtDe;
TextField txtAssunto;
TextField txtUsername;
PasswordField txtSenha;
Button btoEnviar;
Label lblHostServer;
Label lblPara;
Label lblDe;
Label lblAssunto;
Label lblUserName;
Label lblSenha;
Text mensagem;
// tabela de arquivos anexados
TableView<ArquivoModel> tabelaAnexos;
// lista de arquivos exibidos pela tabela
ObservableList<ArquivoModel> listAnexos;
// widget do javafx que gera tags html
HTMLEditor htmlEditor;
Scene scene;
public JanelaEnviar(EventHandler<ActionEvent> eventControler) {
// TODO Auto-generated constructor stub
this.setAlignment(Pos.CENTER);
this.setVgap(5);
this.setHgap(5);
this.setPadding(new Insets(10));
txtHostServer = new TextField("smtp.gmail.com");
txtPara = new TextField();
txtDe = new TextField();
txtAssunto = new TextField();
txtUsername = new TextField();
txtSenha = new PasswordField();
btoEnviar = new Button("Enviar");
btoEnviar.setOnAction(eventControler);
lblHostServer = new Label("SMTP Server:");
lblPara = new Label("Para:");
lblDe = new Label("De:");
lblAssunto = new Label("Assunto:");
lblUserName = new Label("Login:");
lblSenha = new Label("Senha:");
mensagem = new Text();
htmlEditor = new HTMLEditor();
htmlEditor.setPrefHeight(430);
// node, col, row
this.add(lblHostServer, 0, 0);
this.add(txtHostServer, 1, 0);
this.add(lblPara, 0, 1);
this.add(txtPara, 1, 1);
this.add(lblDe, 0, 2);
this.add(txtDe, 1, 2);
this.add(lblAssunto, 0, 3);
this.add(txtAssunto, 1, 3);
this.add(lblUserName, 0, 4);
this.add(txtUsername, 1, 4);
this.add(lblSenha, 0, 5);
this.add(txtSenha, 1, 5);
this.add(setUpTabelaAnexos(), 0, 6, 2, 1);
this.add(htmlEditor, 0, 7, 2, 1);
VBox vBox = new VBox(5, btoEnviar, mensagem);
vBox.setAlignment(Pos.CENTER);
this.add(vBox, 0, 8, 2, 1);
scene = new Scene(this);
}
// método auxiliar de configuraçã da tabela
private Node setUpTabelaAnexos() {
listAnexos = FXCollections.observableArrayList();
// vincula a list na tabela
tabelaAnexos = new TableView<>(listAnexos);
// mensagem quando a tabela estiver vazia
tabelaAnexos.setPlaceholder(new Label("Nenhum Arquivo Anexado"));
// a tabela tera 2 colunas: nome do arquivo e outra coluna com um botão em cada
// linha para excluir o anexo,
// caso o usuário mude de ideia
// configurando a coluna nome do arquivo
TableColumn<ArquivoModel, String> colNomeArquivo = new TableColumn<>("Tabela de Anexos");
// especifica o tipo de dado da coluna e em qual campo do objeto ele está
colNomeArquivo.setCellValueFactory(new PropertyValueFactory<>("nomeArquivo"));
colNomeArquivo.setPrefWidth(450);
// coluna utilitária que possui um botão remover em cada linha
TableColumn<ArquivoModel, ArquivoModel> colRemoveAnexo = new TableColumn<>();
colRemoveAnexo.setPrefWidth(80);
colRemoveAnexo.setCellValueFactory(param -> new ReadOnlyObjectWrapper<>(param.getValue()));
// configura o conteudo da coluna com um objeto TableCell personalizado
colRemoveAnexo.setCellFactory(coluna -> new TableCell<ArquivoModel, ArquivoModel>() {
final Button btoRemoveAnexo = new Button("X");
// metodo updateItem é chamado automaticamente quando se constroi a tabela
@Override
protected void updateItem(ArquivoModel arquivoAnexo, boolean empty) {
super.updateItem(arquivoAnexo, empty);
// se a linha for vazia, não faz nada
if (arquivoAnexo == null) {
setGraphic(null);
return;
}
// se tiver registro na linha, configura o botão
setGraphic(btoRemoveAnexo);
// toda vez quando o botão é clicado, o respectivo anexo é removido
btoRemoveAnexo.setOnAction(event -> getTableView().getItems().remove(arquivoAnexo));
};
});
// adiciona as coluna na tabela
tabelaAnexos.getColumns().addAll(colNomeArquivo, colRemoveAnexo);
tabelaAnexos.setPrefHeight(150);
// configurando o botão anexar
Button btoAddAnexo = new Button("Anexar...");
// registrando o evento de ação para quando o botão for acionado pelo usuário
btoAddAnexo.setOnAction(event -> {
try {
// dialog para seleção de arquivos
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("Escolher Anexo");
// exibe a dialog de seleção de arquivos vinculada à JanelaEnviar
// quando o usuário fecha a dialog de seleção ela retorna um objeto java.io.File
Path anexo = fileChooser.showOpenDialog(((Node) event.getSource()).getScene().getWindow()).toPath();
// verifica se o anexo realmente existe
if (Files.exists(anexo)) {
// extrai o tipo de dado que o anexo contem
String mimeType = Files.probeContentType(anexo);
System.out.printf("mime type %s", mimeType);
// converte o anexo em byte[]
byte[] conteudo = Files.readAllBytes(anexo);
// extrai o nome do anexo
String nomeAnexo = anexo.getFileName().toString();
// cria o objeto ArquivoModel, utilitario para manipular os anexos
ArquivoModel novoAnexo = new ArquivoModel(nomeAnexo, conteudo, mimeType);
// adiciona o anexo na lista vinculada à tabela
listAnexos.add(novoAnexo);
}
} catch (NullPointerException | IOException e) {
e.printStackTrace();
}
});
// colaca a tabela e o botão addAnexo em uma VBox e retorna
VBox vBoxTabelaAnexo = new VBox(5, tabelaAnexos, btoAddAnexo);
return vBoxTabelaAnexo;
}
// retorna os anexos
ArquivoModel[] getAnexos() {
return listAnexos.toArray(new ArquivoModel[listAnexos.size()]);
}
void setMensagemDeSucesso(String msg) {
mensagem.setFill(Color.GREEN);
mensagem.setText(msg);
}
void setMensagemDeErro(String msg) {
mensagem.setFill(Color.RED);
mensagem.setText(msg);
}
}
EventoEnviarEmail.java
A classe EventoEnviarEmail gerencia os eventos do usuário que ocorram na classe JanelaEnviarEmail. Os objetos da API JavaMail são usados aqui:
package main;
//IMPORTS OMITIDOS
//Controle de Eventos da JanelaEnviar
public class EventoEnviarEmail implements EventHandler{
JanelaEnviar janelaEnviar;
String hostServer;
String para;
String de;
String assunto;
String username;
String senha;
String conteudoHtmlMensagem;
ArquivoModel[] anexos;
public void handle(ActionEvent event) {
// TODO Auto-generated method stub
preencherCampos();
try {
enviarEmail();
janelaEnviar.setMensagemDeSucesso("Email Enviado com Sucesso");
System.out.println("OK");
}
catch (UnsupportedEncodingException e) {
janelaEnviar.setMensagemDeErro("Caracteres não suportados na mensagem");
e.printStackTrace();
}
catch (AuthenticationFailedException e) {
//endereco invalido
janelaEnviar.setMensagemDeErro("Usuário ou senha Inválidos");
e.printStackTrace();
}
catch (AddressException e) {
//endereco invalido
janelaEnviar.setMensagemDeErro("Formato de endereço de email Inválido");
e.printStackTrace();
}
catch (MessagingException e) {
//endereco invalido
janelaEnviar.setMensagemDeErro("Erro ao enviar a mensagem");
e.printStackTrace();
}
catch (Exception e) {
// TODO: handle exception
janelaEnviar.setMensagemDeErro("Erro ao enviar a mensagem");
e.printStackTrace();
}
finally {
janelaEnviar.txtSenha.setText("");
}
}
private void enviarEmail() throws AddressException, MessagingException, UnsupportedEncodingException {
// TODO Auto-generated method stub
Authenticator authenticator = new MeuAutenticador(username, senha);
//configura objeto properties
Properties props = new Properties();
props.put("mail.smtp.host", hostServer);
props.put("mail.smtp.host", "smtp.gmail.com");
props.put("mail.smtp.socketFactory.port", "465"); //porta ssl
props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); //especifica classe para criar SMTP Socket
props.put("mail.smtp.auth", "true"); //autenticação requerida
//obtem um objeto Session sob as credenciais e propriedades especificadas
Session session = Session.getInstance(props, authenticator);
Message mensagem = new MimeMessage(session);
Address enderecoDe = new InternetAddress(username, de); //address except
Address enderecoPara = new InternetAddress(para);
mensagem.setFrom(enderecoDe); //messaging excep
mensagem.setRecipient(Message.RecipientType.TO, enderecoPara);
mensagem.setSubject(assunto);
//coloca o conteudo e os anexos na mensagem
setConteudoMensagem(mensagem, anexos);
Transport.send(mensagem); //auth failed except
}
private void setConteudoMensagem(Message mensagem, ArquivoModel[] arquivos) throws MessagingException {
Multipart multipart = new MimeMultipart();
//cria um BodyPart representando um conteudo HTML
BodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setContent(conteudoHtmlMensagem, "text/html");
//adiciona o BodyPart nop Multipart
multipart.addBodyPart(messageBodyPart);
messageBodyPart = new MimeBodyPart();
//DataHandler para operações diversas nos diferentes tipos de dados
DataHandler dataHandler = null;
//loop: cria um BodyPart para cada anexo e adiciona-o no Multipart
for(ArquivoModel anexo : arquivos) {
dataHandler = new DataHandler(anexo.getConteudo(), anexo.getMimeType());
messageBodyPart = new MimeBodyPart();
messageBodyPart.setDataHandler(dataHandler);
messageBodyPart.setFileName(anexo.getNomeArquivo());
multipart.addBodyPart(messageBodyPart);
}
//adiciona o MUltipart na mensagem
mensagem.setContent(multipart);
}
private void preencherCampos() {
// TODO Auto-generated method stub
hostServer = janelaEnviar.txtHostServer.getText();
para = janelaEnviar.txtPara.getText();
de = janelaEnviar.txtDe.getText();
assunto = janelaEnviar.txtAssunto.getText();
username = janelaEnviar.txtUsername.getText();
senha = janelaEnviar.txtSenha.getText();
anexos = janelaEnviar.getAnexos();
//extrai o conteudo html de HTMLEditor na forma de uma String
conteudoHtmlMensagem = janelaEnviar.htmlEditor.getHtmlText();
}
}
MeuAutenticator.java
No JavaMail, para logar em uma conta de email no servidor remoto, você precisa sobrescrever o método getPasswordAuthentication()da classe javax.mail.Authenticator porque é esse método que o objeto javax.mail.Session chama para efetivar o login. Se a tentativa de login feita por Session falhar, a exceção javax.mail.AuthenticationFailedException é lançada:
package main;
//IMPORTS OMITIDOS
public class MeuAutenticador extends Authenticator {
private final PasswordAuthentication passwordAuthentication;
//passamos login e senha no construtor
public MeuAutenticador(String login, String senha) {
super();
passwordAuthentication = new PasswordAuthentication(login, senha);
}
//toda aplicação deve sobrescrever getPasswordAuthentication()
@Override
protected PasswordAuthentication getPasswordAuthentication() {
// TODO Auto-generated method stub
return passwordAuthentication;
}
}
Main.java
Na classe Main iniciamos a aplicação. Para inciar uma aplicação JavaFx, sobrescrevemos o método start() da classe abstrata javafx.application.Application:
package main;
import javafx.application.Application;
import javafx.stage.Stage;
//Enviando conteudo HTML
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
// TODO Auto-generated method stub
EventoEnviarEmail evento = new EventoEnviarEmail();
JanelaEnviar janelaEnviar = new JanelaEnviar(evento);
evento.janelaEnviar = janelaEnviar;
primaryStage.setTitle("Cliente de Email com JavaFX");
primaryStage.setScene(janelaEnviar.scene);
primaryStage.show();
}
public static void main(String[] args) {
// TODO Auto-generated method stub
launch(args);
}
}
Agora já podemos executar o projeto. O resultado é a aplicação que exibimos no início deste post:
Após preencher todos os campos, envie a mensagem ao destinatário clicando no botão enviar.