Palestra Java One

O JavaOne, Oracle Develop e Oracle Open World 2010 foi muito bom, uma pena que não pude participar como gostaria. Estava alocado em um projeto muito importante que saiu na Oracle Partners Ecosystem. O pouco que participei valeu a pena.

Participei de uma reunião de JUG Leaders muito legal com o Bruno Souza. Estava presente o Stephen Chin – JUG Leader do Silicon Valley JavaFX User Group e vários líderes de todo o Brasil. A gravação está disponível no seguinte endereço: http://www.ustream.tv/recorded/11307812 e fotos em: http://picasaweb.google.com/globalcodebrasil/JavaOneBrasilEncontroDeJavaUserGroups#

Pra quem quiser mais informações aqui tem um resumo geral do Java One feito pela Globalcode. As palestras do Java One estão disponíveis aqui.

Uma crítica que tenho a fazer do evento é que o Java One estava um pouco escondido, mas creio que a Oracle deve ter percebido a força da comunidade Java no Brasil e com certeza no próximo evento haverá um destaque maior.

Nesse evento aproveitei um voucher que a Accurate me deu para fazer a prova Oracle SOA Foundation Practitioner e tirar a certificação de Oracle Service Oriented Architecture Infrastructure Implementation Certified Expert!

Abaixo segue minha palestra de Blu-ray no Java One. Agradeço a presença de todos, não esperava tanta gente e em breve disponibilizo as fotos. O pessoal do Java Noroeste estava em massa também (Éver, Egberto, Kólem, Junior, Bruno, Lucas, Caio)! Agradecimento especial ao Carlos Fernando Gonçalves que é o JUG Leader do Java Noroeste e um dos colaboradores com o desenvolvimento de Blu-ray, TV Digital, Java ME e afins…

Em breve disponibilizo as fotos!

Aplicação completa JME com LWUIT e Floggy

Hoje estou disponibilizando para todos o acesso ao fonte de uma aplicação que a gente fez em apenas em alguns dias… para ser sincero código mesmo foi feito em apenas 4 dias (ou melhor 4 noites), tivemos mais três dias para escolha do nome,  um dia para definição da equipe, definição de logotipo e definições do caso de uso e 2 dias eu descansei e trabalhei em outras coisas… Então foram 10 dias (somente tempo livre) contando todas as etapas para a aplicação completa. A idéia genial do projeto surgiu do Egberto, alguns casos de uso e o vídeo também foi feito por ele,  testes, casos de uso, colaboração com idéias e algumas imagens como o logotipo foram feitos pelo Éver. E eu fiz o código.

Queríamos participar do concurso da Nokia, mas não deu tempo de assinar a aplicação e ela não ficou como queríamos, então não ganhamos, mas valeu como esperiência. Como estávamos prevendo o desenvolvimento com mais gente e acabou não dando certo, eu adotei uma estrutura de pacotes semelhante ao desenvolvimento web, já que a maioria que entrou no projeto vinha desse contexto e não de desenvolvimento mobile. O código ainda tem alguns bugs, não está limpando alguns campos, mas a aplicação está funcional, embora não esteja otimizada. Tem também alguns erros de inglês no vídeo… vamos corrigir depois :)

Utilizamos LWUIT e Floggy de framework para a aplicação. Abaixo está a descrição do projeto.

GREENHOUSE

Sua consciência ecológica!


“O efeito estufa é gerado pela derrubada de florestas, lançamento de gases poluentes na atmosfera, principalmente os que resultam da queima de combustíveis fósseis. Esse efeito ocasiona o super aquecimento do nosso planeta. O aplicativo greenhouse será sua consciência ecológica, informando a você a quantidade de árvores necessárias para consumir o CO2 produzido, de acordo com o meio de transporte automotivo.”

O projeto foi feito com Netbeans 6.9. O código fonte encontra-se disponível para download pelo subversion: http://gvlabs.org/svn/mobile/Greenhouse/

Se você deseja somente instalar no seu celular, segue o download da aplicação: http://www.thiagovespa.com.br/apps/Greenhouse.zip

Se você não sabe utilizar o subversion no Netbeans, aqui tem um breve tutorial: http://www.thiagovespa.com.br/blog/2010/09/20/subversion-no-netbeans/

Instalação do ambiente:

  1. Fazer download do Netbeans Completo (Já vem com o JME) e instalar. Quem tiver interesse pode instalar o JME SDK 3.0 também: http://java.sun.com/javame/downloads/sdk30.jsp
  2. Abrir o Netbeans, ir em Tools, Plugins e atualiza-lo.
  3. Fazer o download do Perl: http://strawberry-perl.googlecode.com/files/strawberry-perl-5.12.0.1.msi e instalar
  4. Reiniciar o computador
  5. Baixar o SDK da Nokia Symbian^3 0.8: http://www.forum.nokia.com/info/sw.nokia.com/id/ec866fab-4b76-49f6-b5a5-af0631419e9c/S60_All_in_One_SDKs.html
  6. Instalar o SDK da Nokia. A partir de agora você já pode abrir o emulador da Nokia
  7. Abrir o Emulador e configurar data e hora. Pode usar o teclado do computador, não precisa usar somente o teclado do celular.

Configuraçõe Adicionais – Netbeans

Configurar o emulador da Nokia

  1. Tools, Java Platform, Add Platform, Java ME MIDP Platform, Next
  2. Verificar se encontrou o emulador da Nokia, Next
  3. Finish

Configurar a lib do LWUIT

  1. Faça o Download do LWUIT em: http://java.sun.com/javame/technology/lwuit/ no botão Download LWUIT
  2. Descompacte ele em uma pasta
  3. Vá no netbeans, Tools, Libraries
  4. New Library…, Library Name: LWUIT, Library Type: Class Libraries
  5. Add Jar/Folder, Escolher o LWUIT.jar que está na pasta lib do LWUIT, Apertar Ok

Configurar a lib do Floggy

  1. Faça o Download do Floggy em: http://floggy.sourceforge.net/download.html na seção Main Bundle
  2. Descompacte ele em uma pasta
  3. Vá no netbeans, Tools, Libraries
  4. New Library…, Library Name: Floggy, Library Type: Class Libraries
  5. Add Jar/Folder, Escolher o floggy-persistence-framework.jar que está na pasta lib do Floggy, Apertar Ok
  6. Abrir o arquivo build.xml (Visualizar por Window, Files) e mudar a propriedade floggy.path para o caminho da instalação do floggy (Favor não commitar o build.xml com suas alterações)

Configurar o Checkstyle (somente para commiters)

  1. Ir em Tools, Plugin
  2. Settings, Add
  3. Name: Checkstyle, URL: http://www.sickboy.cz/checkstyle/autoupdate/autoupdate-2.xml – OK
  4. Avaliable Plugins, Reload Catalog
  5. Selecionar Checkstyle beans plugin e library, Install
  6. Confimar as opções até o final

Espero que gostem. Quem quiser contribuir para melhorar esse projeto é só me avisar que eu libero acesso como commiter no repositório.

Editor de BDJO para autoração de blu-ray

Ultimamente estou brincando um pouco com editoração de blu-ray, fiz alguma coisas bem bacanas, mas encontrei algumas pedras no caminho.

As melhores aplicações são extramemente caras e apesar de serem fáceis de se trabalhar, elas ocultam o que realmente geram. Os utilitários gratuitos como os do HD Cookbook são via linha de comando e complicados de se trabalhar. Enfrentando essas dificuldades, resolvi criar algumas aplicações para me ajudar a verificar o que as aplicações proprietárias geram e facilitar a autoração de blu-ray de nível profissional sem a necessidade de desembolsar dinheiro.

Em um outro post (no Globalcoders também) eu expliquei como criar seu primeiro aplicativo pra Blu-ray utilizando o JMESDK 3.0. Ao executar os procedimentos, é gerado na pasta build/deploy/BDMV/BDJO do seu projeto um arquivo 00000.bdjo. Esse arquivo é o Blu-ray Disc™ Java Object. Dentro dele tem informações de como executar sua aplicação Java, configurações de acesso à playlists, identificadores, classe inicial, visibilidade entre outros. Infelizmente, não há como editá-lo pela IDE.

Para podermos editar esse arquivo de maneira gráfica resolvi criar um editor, ainda está na versão alpha, portanto, utilize por conta e risco :) . Pretendo criar outros editores em breve…

Esse editor já cria, abre, edita (com exceção das apps) e exporta para os formatos BDJO, JavaFX e XML baseado em códigos do HDCookbook. O que falta ainda na aplicação:

  • Correção de bugs críticos
  • Edição das aplicações associadas ao BDJO. Por enquanto só insere e remove.
  • Internacionalização
  • Testes
  • Melhorar o código
  • Validação dos campos, incluindo tamanho
  • Melhorar a interface gráfica
  • Colocar combo de seleção de idiomas ao invés de campo de texto
  • Ajuda e documentação
  • Melhorar descrição dos campos
  • Criar função “Desfazer”
  • Carregar alguns valores padrão
  • Criar renderes personalizados para tabelas

Clique para executar a aplicação:

Abaixo está o screenshot da aplicação pra quem não gosta de executar :D

BDJO Editor

BDJO Editor

Se você gostou e deseja contribuir para a criação dessas aplicações, me ajude efetuando uma doação ou contribuindo de como você achar melhor.

Esse post encontra-se disponível também no Globalcoders.

Passos iniciais em Java para Blu-ray

Criar uma aplicação para Blu-ray Java (BD-J) é uma tarefa simples, basta implementar uma interface javax.tv.xlet.Xlet que esta presente na API Java TV que faz parte da especificação do BD-Java

O ciclo de vida dos BD-J Xlets é semelhante à qualquer aplicação embarcada. Após a chamada do construtor, o Xlet entra no estado de carregado. O método initXlet() é chamado, e o Xlet passa para estado pausado até o momento que o método startXlet() seja chamado.

Para testes da aplicação é necessário um player que suporte a execução de arquivos de blu-ray. Pode-se ser utilizado um desses players: Corel com o WinDVD, CyberLink com PowerDVD e ArcSoft com o ToTalMedia Theatre.

No desenvolvimento você pode utilizar o Netbeans com o plugin de mobile instalado ou Java Platform Micro Edition Software Development Kit 3.0 (recomendado) que pode ser encontrado em: http://java.sun.com/javame/downloads/sdk30.jsp

Após instalado o JMESDK 3.0 é necessário configurar o player do BD-Java. Basta ir em Tools, Options, Miscellaneous e acessar a aba BD-J que é onde você irá configurar o caminho do player instalado.

Para criar um novo projeto você deve selecionar File, New Project, CDC Application, dar um nome pro projeto, selecionar Next, e em Java Platform, selecionar Stubs for BD-J Platform, Finish.

Pronto! Agora é só brincar com a API do Havi para criar a parte gráfica. Você também pode utilizar as classes do Personal Basis Profile do CDC e do Globally Executable MHP. No próximo post irei abordar a exibição de imagens e componentes gráficos.

Até a próxima.

Agradecimentos ao Carlos Fernando Gonçalves (http://twitter.com/mercuriocfg) JUG Leader do Java Noroeste (http://javanoroeste.com.br) pelo levantamento das informações dos players de Blu-ray. Posts do Carlos Fernando Gonçalves.

Esse post também se encontra em: http://blog.globalcode.com.br/2010/07/passos-iniciais-em-java-para-blu-ray.html

FileChooser com LWUIT

O LWUIT é um framework desenvolvido pela Sun Microsystems para facilitar o desenvolvimento de interface gráficas em celulares. Ele é bem parecido com o Swing para desktop.

Fiquei conhecendo esse framework graças ao Antônio Marin Neto em seu blog, que aborda características do LWUIT como Recursos, Estabilidade, Desempenho e outros. Eu achei o LWUIT muito fácil de usar e com vários recursos, embora o tempo para iniciar um programa feito nele é um pouco grande. Nada que um loading screen não resolva.

A criação do FileChooser veio da necessidade de trabalhar com arquivos em um projeto que estou desenvolvendo para um Wiki móvel. Em breve disponibilizarei os fontes do projeto como open source para o pessoal poder contribuir.

O primeiro passo foi utilizar a JSR 75 para manipular os arquivos. Para verificar se o dispositivo tem suporte a essa JSR, você pode utilizar o seguinte código:

public static boolean isJSR75Available() {
    // Verifica se a JSR 75 está disponível
    return System.getProperty("microedition.io.file.FileConnection.version") != null;
}

Os próximos código terão referências às classes Language e ExceptionHandler. A primeira foi utilizada para localização utilizando o editor de resources do LWUIT e a segunda é responsável por processar exceções. Posteriormente eu explico o funcionamento dessas duas classes. Para funcionar o código sem elas, basta você realizar o tratamento de erros da sua maneira e substituir a chamada de Language.getLocalizedString(“…”) por alguma outra String.

Agora vamos criar uma classe utilitária (FileUtil) para trabalhar com arquivos. É necessário pegar o separador de arquivos, qual é a string de diretório que representa o nível superior e o prefixo para acessar arquivos.

public final static String FILE_SEPARATOR = (System.getProperty("file.separator") != null) ? System.getProperty("file.separator") : "/";
public final static String TOP_DIR = "..";
public final static String FILE_PREFIX = "file:///";

Para verificar se o caminho passado é uma raiz, utilizamos um workaround.

public static boolean isRoot(String path) {
    // Operação sobre o path ao invés de verificar na lista de roots
    // Verifica se o primeiro separador de arquivo é o último caractere
    if (path != null && path.indexOf(FileUtil.FILE_SEPARATOR) != path.length() - 1) {
        return false;
    }
    return true;
}

Depois é só utilizarmos o Connector.open para obter um FileConnection e executar as operações em arquivos.

Com isso temos o seguinte arquivo:

package br.com.thiagovespa.mobwiki.util;</p>
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Vector;

import javax.microedition.io.Connector;
import javax.microedition.io.file.FileConnection;

/**
* Classe para manipulação de arquivos
*
* @author Thiago Galbiatti Vespa
*
*/

public final class FileUtil {
    public final static String FILE_SEPARATOR = (System
        .getProperty("file.separator") != null) ? System
        .getProperty("file.separator") : "/";

    public final static String TOP_DIR = "..";
    public final static String FILE_PREFIX = "file:///";

    /**
    * Verifica se o caminho é uma raiz baseado na string passada, pode resultar
    * em resultado falso caso seja passada um caminho inválido
    *
    * @param path
    *            caminho a ser verificado
    * @return verdadeiro se o formato da string for raiz
    */

    public static boolean isRoot(String path) {
        // Operação sobre o path ao invés de verificar na lista de roots
        // Verifica se o primeiro separador de arquivo é o último caractere
        if (path != null
                && path.indexOf(FileUtil.FILE_SEPARATOR) != path.length() - 1) {
            return false;
        }
        return true;
    }
   
    /**
    * Cria um diretório
    *
    * @param path
    *            diretório a ser criado
    * @return true se o diretorio foi criado, false caso contrário
    */

    public static boolean createDir(String path) {
        FileConnection newDir = null;
        try {
            newDir = (FileConnection) Connector.open(FileUtil.FILE_PREFIX
                + path + FileUtil.FILE_SEPARATOR, Connector.READ_WRITE);
            if (!newDir.exists()) {
                newDir.mkdir();
                return true;
            } else {
                ExceptionHandler.handleException(new IOException(Language
                    .getLocalizedString("dirAlreadyExist")));
            }
        } catch (IOException e) {
            ExceptionHandler.handleException(e);
        } catch (SecurityException e) {
            ExceptionHandler.handleException(e, Language
                .getLocalizedString("securityExceptionDesc"));
        } finally {
            if (newDir != null) {
                try {
                    newDir.close();
                } catch (IOException e) {
                    ExceptionHandler.handleException(e);
                }
            }
        }
        return false;
    }
   
    /**
    * Cria um novo arquivo
    *
    * @param path
    *            arquivo a ser criado
    * @return true se o arquivo foi criado, false caso contrário
    */

    public static boolean createNewFile(String path, String content) {
        FileConnection newFile = null;
        DataOutputStream dos = null;
        try {
            newFile = (FileConnection) Connector.open(FileUtil.FILE_PREFIX
                + path, Connector.READ_WRITE);
            if (!newFile.exists()) {
                newFile.create();
                dos = newFile.openDataOutputStream();
                dos.writeUTF(content);
                dos.flush();
                return true;
            } else {
                ExceptionHandler
                    .handleException(new IOException(Language
                    .getLocalizedString("file")
                    + path
                    + Language
                    .getLocalizedString("already exists!")));
            }
        } catch (IOException e) {
            ExceptionHandler.handleException(e);
        } catch (SecurityException e) {
            ExceptionHandler.handleException(e, Language
                .getLocalizedString("securityExceptionDesc"));
        } finally {
            try {
                if (newFile != null) {
                    newFile.close();
                }
                if (dos != null) {
                    dos.close();
                }
            } catch (IOException e) {
                ExceptionHandler.handleException(e);
            }
        }
        return false;
    }
   
    /**
    * Atualiza arquivo
    *
    * @param path
    *            arquivo a ser atualizado
    * @return true se o arquivo foi atualizado, false caso contrário
    */

    public static boolean updateFile(String path, String content) {
        FileConnection file = null;
        DataOutputStream dos = null;
        try {
            file = (FileConnection) Connector.open(FileUtil.FILE_PREFIX + path,
                Connector.READ_WRITE);
            if (!file.exists()) {
                // Cria se não existe
                file.create();
            } else {
                // Trunca se já existe
                file.truncate(0);
            }
            dos = file.openDataOutputStream();
            dos.writeUTF(content);
            dos.flush();
            return true;
        } catch (IOException e) {
            ExceptionHandler.handleException(e);
        } catch (SecurityException e) {
            ExceptionHandler.handleException(e, Language
                .getLocalizedString("securityExceptionDesc"));
        } finally {
            try {
                if (file != null) {
                    file.close();
                }
                if (dos != null) {
                    dos.close();
                }
            } catch (IOException e) {
                ExceptionHandler.handleException(e);
            }
        }
        return false;
    }

    public static boolean existsFile(String path) {
        FileConnection file = null;
        try {
            file = (FileConnection) Connector.open(FileUtil.FILE_PREFIX + path,
                Connector.READ);
            if (file.exists()) {
                return true;
            }
        } catch (IOException e) {
            ExceptionHandler.handleException(e);
        } catch (SecurityException e) {
            ExceptionHandler.handleException(e, Language
                .getLocalizedString("securityExceptionDesc"));
        } finally {
            try {
                if (file != null) {
                    file.close();
                }
            } catch (IOException e) {
                ExceptionHandler.handleException(e);
            }
        }
        return false;
    }

    /**
    * Lê um arquivo
    *
    * @param path
    *            arquivo a ser lido
    * @return conteúdo do arquivo
    */

    public static String loadFile(String path) {
        FileConnection file = null;
        DataInputStream dis = null;
        String retVal = null;
        try {
            file = (FileConnection) Connector.open(FileUtil.FILE_PREFIX + path,
                Connector.READ);
            if (file.exists()) {
                dis = file.openDataInputStream();
                retVal = dis.readUTF();
            } else {
                ExceptionHandler.handleException(new IOException("File " + path
                    + " do not exists!"));
            }
        } catch (IOException e) {
            ExceptionHandler.handleException(e);
        } catch (SecurityException e) {
            ExceptionHandler.handleException(e, Language
                .getLocalizedString("securityExceptionDesc"));
        } finally {
            try {
                if (file != null) {
                    file.close();
                }
                if (dis != null) {
                    dis.close();
                }
            } catch (IOException e) {
                ExceptionHandler.handleException(e);
            }
        }
        return retVal;
    }

    /**
    * Lê um diretório
    *
    * @param path
    *            diretório a ser lido
    * @return lista
    */

    public static String[] loadDir(String path, String pattern) {
        FileConnection dir = null;
        String[] retVal = null;
        Vector files = new Vector();
        try {
            dir = (FileConnection) Connector.open(FileUtil.FILE_PREFIX + path,
                Connector.READ);
            if (dir.exists()) {
                Enumeration en = dir.list(pattern, true);
                while (en.hasMoreElements()) {
                    String object = (String) en.nextElement();
                    files.addElement(object);
                }
                if (files != null) {
                    retVal = new String[files.size()];
                    files.copyInto(retVal);
                }
            } else {
                ExceptionHandler.handleException(new IOException("File " + path
                    + " do not exists!"));
            }
        } catch (IOException e) {
            ExceptionHandler.handleException(e);
        } catch (SecurityException e) {
            ExceptionHandler.handleException(e, Language
                .getLocalizedString("securityExceptionDesc"));
        } finally {
            try {
                if (dir != null) {
                    dir.close();
                }
            } catch (IOException e) {
                ExceptionHandler.handleException(e);
            }
        }
        return retVal;
    }

    /**
    * Remove um diretório
    *
    * @param path
    *            diretório a ser removido
    * @return true se removido e false caso contrário
    */

    public static boolean deleteDir(String path) {
        FileConnection dir = null;
        try {
            dir = (FileConnection) Connector.open(FileUtil.FILE_PREFIX + path,
                Connector.READ_WRITE);
            if (dir.exists()) {
                Enumeration en = dir.list("*", true);
                while (en.hasMoreElements()) {
                    String object = (String) en.nextElement();
                    if (object.endsWith(FileUtil.FILE_SEPARATOR)) {
                        deleteDir(path + object);
                    } else {
                        deleteFile(path + object);
                    }
                }
                dir.delete();
                dir.close();
                return true;
            } else {
                ExceptionHandler.handleException(new IOException(Language
                    .getLocalizedString("file")
                    + path + Language.getLocalizedString("doNotExist")));
            }
        } catch (IOException e) {
            ExceptionHandler.handleException(e);
        } catch (SecurityException e) {
            ExceptionHandler.handleException(e, Language
                .getLocalizedString("securityExceptionDesc"));
        } finally {
            try {
                if (dir != null) {
                    dir.close();
                }
            } catch (IOException e) {
                ExceptionHandler.handleException(e);
            }
        }
        return false;
    }

    /**
    * Remove um arquivo
    *
    * @param path
    *            arquivo a ser removido
    * @return true se removido e false caso contrário
    */

    public static boolean deleteFile(String path) {
        FileConnection file = null;
        try {
            file = (FileConnection) Connector.open(FileUtil.FILE_PREFIX + path,
                Connector.READ_WRITE);
            if (file.exists()) {
                file.delete();
                file.close();
                return true;
            } else {
                ExceptionHandler.handleException(new IOException(Language
                    .getLocalizedString("file")
                    + path + Language.getLocalizedString("doNotExist")));
            }
        } catch (IOException e) {
            ExceptionHandler.handleException(e);
        } catch (SecurityException e) {
            ExceptionHandler.handleException(e, Language
                .getLocalizedString("securityExceptionDesc"));
        } finally {
            try {
                if (file != null) {
                    file.close();
                }
            } catch (IOException e) {
                ExceptionHandler.handleException(e);
            }
        }
        return false;
    }

}

No próximo post a gente parte para a parte gráfica do FileChooser.

Até a próxima!