Encontrando JAR à partir do nome da classe
Um problema que sempre atormentou minha vida foi tentar descobrir em qual JAR está uma determinada classe. Até o momento eu recorria ao http://www.findjar.com, http://www.jarfinder.com/ ou Google. O problema é que nem sempre o JAR é encontrado ou está em versão errada. Para resolver esse tormento resolvi criar um programinha que consiste em buscar à partir de um caminho todos os arquivos JAR e procurar dentro dele à classe que eu quero.
««« Clique aqui para ler o restante do conteúdo: Encontrando JAR à partir do nome da classe »»»
Sessão serializável e explorável
Aproveitando o embalo do post: http://www.thiagovespa.com.br/blog/2011/03/31/violando-o-encapsulamento/ resolvi criar uma aplicação para explorar a sessão de uma aplicação Web e verificar quais atributos são Serializáveis ou não. Para quem já precisou rodar uma aplicação em cluster com replicação de sessão sabe que é fundamental que todos os atributos que estão na sessão implemente a interface Serializable. Caso contrário, o erro NotSerializableException irá ocorrer.
Infelizmente existem bibliotecas de terceiros e de frameworks que não temos o código e nem documentação suficiente para saber se o atributo é serializável ou não, mas felizmente, temos maneiras de verificar isso utilizando código. Para resolver esse problema criei uma servlet que permiti navegarmos nas classes utilizadas nos atributos de sessão e explorar o conteúdo dos objetos.
Para recuperar as informações das classes, utilizei um map que associa a classe com suas informações. Nesse map estarão todas as classes envolvidas, seja por herança (linha 14) ou por composição (linha 17).
public void getAllFields(Class c, String fieldName) {
if (mapOfClasses.containsKey(c)) {
return;
}
Field[] fields = c.getDeclaredFields();
List fieldInfoList = new ArrayList();
for (Field f : fields) {
f.setAccessible(true);
fieldInfoList.add(new FieldInfo(f.getName(), f.getType(), f
.getModifiers()));
}
mapOfClasses.put(c, fieldInfoList);
if (c.getSuperclass() != null) {
getAllFields(c.getSuperclass(), "extends");
}
for (FieldInfo aFieldInfo : fieldInfoList) {
getAllFields(aFieldInfo.getFieldClass(), aFieldInfo.getFieldName());
}
}
Esse método é chamado recursivamente para todos os tipos de atributos e para a classe pai. Dessa forma, o map fica composto por todas as classes envolvidas na sessão Web. Essas informações são auxiliares para verificar quais classes implementam a interface Serializable, e quais são os atributos envolvidos e se eles implementam também.
Os recursos mais bacanas implementados foram: navegar pelos atributos de sessão, calcular o tamanho que cada atributo fica em memória (isso permite análise para otimização de uso de sessão) e verificar quais atributos são serializáveis de maneira interativa. E para isso necessitamos verificar se o objeto é serializável ou não. Com isso seria necessário verificar se todos os seus atributos (não estáticos e blabla
) acessíveis são serializáveis, se a classe pai não for serializável, ela tem que ter um construtor padrão, entre outros. Existem vários aspectos a serem verificados. Mais informações você pode encontrar no próprio javadoc da interface Serializable. Para facilitar essa análise e realizá-la de maneira mais simples, basta serializar o objeto
. Se tivermos um NotSerializableException significa que a classe não é serializável, caso contrário ela é serializável e como já serializamos ela, podemos recuperar o tamanho que ficará em memória. Podemos fazer isso utilizando um ByteArrayOutputStream e gravar o objeto nele. O código é bem simples:
public int getSerialSize(Object o) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream oos;
oos = new ObjectOutputStream(out);
oos.writeObject(o);
oos.close();
return out.toByteArray().length;
}
Dessa maneira fica muito simples analisar os objetos na sessão. Coloquei algumas cores para sinalizar cada objeto e o resultado final é o seguinte:
Dessa forma sabemos que o objeto da classe LocaleMB não é serializável. Podemos clicar no nome da classe para verificar quais atributos estão envolvidos e se ela implementa a interface serializable conforme mostrado abaixo:
Como podemos ver, a classe não está em amarelo, o que significa que ela implementa a interface Serializable, e podemos ver que apenas colocando implements Serializable não resolve o nosso problema. Se navegarmos dentro dos valores do objeto iremos ver algo interessante:
Embora a classe implemente a interface Serializable, um dos seus atributos não é serializável. Só conseguimos ver essa informação de maneira simples, graças a esse utilitário. E por isso vou disponibilizá-lo, caso alguém tenha problemas de NotSerializableException.
Para colocá-lo no seu projeto Web é muito simples. Copie o jar desse projeto para a pasta WEB-INF/lib (ou bibliotecas, build path, depende da IDE de sua preferência). Se o seu projeto utilizar Servlet 3.0, não é necessária nenhuma configuração adicional, pois ele já possui o mapeamento para Servlet – @WebServlet(urlPatterns = { “/serialcheck” }). Caso você deseja sobreescrever esse mapeamento ou utiliza uma especificação de Servlet inferior, abra o seu arquivo web.xml e adicione as seguintes linhas:
... <servlet> <servlet-name>SerializableChecker</servlet-name> <servlet-class>br.com.thiagovespa.serializablechecker.SerializableChecker</servlet-class> </servlet> <servlet-mapping> <servlet-name>SerializableChecker</servlet-name> <url-pattern>/serialcheck</url-pattern> </servlet-mapping> ...
Aí é só acessar o endereço: http[s]://<ip>:<porta>/<contexto>/serialcheck (p. ex: http://localhost:7001/portal/serialcheck) e brincar um pouco. Sugestões são bem vindas!
Seu próprio servidor HTTP em Java
Vamos criar um servidor HTTP sem a necessidade de bibliotecas externas. Com isso iremos entender o funcionamento do protocolo HTTP e uso de classes Java de conexão.
Para criarmos esse servidor, precisamos ver como funciona o HTTP. O HTTP é um protocolo baseado em requisição e resposta. O cliente faz uma requisição e o servidor envia uma resposta (simples assim). Normalmente ocorre a comunicação na porta 80, mas isso não é regra. A versão atual é a 1.1 e a especificação completa pode ser encontrada em: http://www.w3.org/Protocols/HTTP/1.1/rfc2616.pdf.
Uma requisição normalmente é composta por:
- uma lista especificando o método (GET, POST, PUT, …), a URI e o protocolo e a versão;
- cabeçalhos de requisição;
- corpo.
De maneira semelhante uma resposta é composta também por três elementos:
- protocolo/versão, código do status e descrição;
- cabeçalhos de resposta;
- corpo.
Para verificar isso, vamos utilizar telnet para fazer uma requisição HTTP para o meu blog. Abra a telnet especificando o endereço e a porta:
telnet www.thiagovespa.com.br 80
Dica: Você pode redirecionar a saída para um arquivo ou para o less para visualizar melhor a resposta dos dados.
Digite a seguinte requsição:
GET /blog/ HTTP/1.1 Accept: text/plain; text/html Accept-Language: pt-br Connection: Keep-Alive Host: www.thiagovespa.com.br User-Agent: Telnet para teste
A linha 1 especifica o tipo do método que no nosso caso é “GET”, com a URI “/blog/” e o protocolo “HTTP/1.1″. As linhas seguintes são os cabeçalhos da requisição. Não há corpo nessa requisição, pois não estamos enviando nenhuma informação adicional (só queremos a página que responde pela URI /blog/). Se, por exemplo, estivéssemos fazendo um POST, poderíamos passar os valores a serem enviados no post no corpo da requisição.
Ao pular uma linha (CRLF) o servidor entende como fim da requisição e irá enviar a resposta. Você deverá obter algo similar a isso:
HTTP/1.1 200 OK Date: Sun, 06 Feb 2011 13:08:51 GMT Server: Apache/2.2.8 (Ubuntu) DAV/2 SVN/1.4.6 mod_jk/1.2.25 mod_python/3.3.1 Python/2.5.2 PHP/5.2.4-2ubuntu5.14 with Suhosin-Patch mod_ruby/1.2.6 Ruby/1.8.6(2007-09-24) mod_ssl/2.2.8 OpenSSL/0.9.8g mod_perl/2.0.3 Perl/v5.8.8 X-Powered-By: PHP/5.2.4-2ubuntu5.14 Set-Cookie: PHPSESSID=1142b7e285308028ff49c8535e4c3027; path=/ X-Pingback: http://www.thiagovespa.com.br/blog/xmlrpc.php Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: text/html; charset=UTF-8 1fad <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="pt-BR" xml:lang="pt-BR"> <head profile="http://gmpg.org/xfn/11"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> ...
A primeira linha é o protocolo da versão com o código de status (200 OK), da linha 2 à linha 10 são os cabeçalhos da resposta e o restante é o corpo com o resultado da página que eu solicitei. Você pode fazer o mesmo pelo Java, criei uma classe simples que faz o trabalho:
package br.com.thiagovespa.http.utils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
/**
* Cliente HTTP simples para somente requisições GET
*
* @author Thiago Galbiatti Vespa - <a
* href="mailto:thiago@thiagovespa.com.br">thiago@thiagovespa.com.br</a>
* @version 1.0
*
*/
public class HttpClient {
/**
* Versão do protocolo utilizada
*/
public final static String HTTP_VERSION = "HTTP/1.1";
private String host;
private int port;
/**
* Construtor do cliente HTTP
* @param host host para o cliente acessar
* @param port porta de acesso
*/
public HttpClient(String host, int port) {
super();
this.host = host;
this.port = port;
}
/**
* Realiza uma requisição HTTP e devolve uma resposta
* @param path caminho a ser feita a requisição
* @return resposta do protocolo HTTP
* @throws UnknownHostException quando não encontra o host
* @throws IOException quando há algum erro de comunicação
*/
public String getURIRawContent(String path) throws UnknownHostException,
IOException {
Socket socket = null;
try {
// Abre a conexão
socket = new Socket(this.host, this.port);
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
// Envia a requisição
out.println("GET " + path + " " + HTTP_VERSION);
out.println("Host: " + this.host);
out.println("Connection: Close");
out.println();
boolean loop = true;
StringBuffer sb = new StringBuffer();
// recupera a resposta quando ela estiver disponível
while (loop) {
if (in.ready()) {
int i = 0;
while ((i = in.read()) != -1) {
sb.append((char) i);
}
loop = false;
}
}
return sb.toString();
} finally {
if (socket != null) {
socket.close();
}
}
}
}
Na linha 51 abrimos uma conexão Socket para o endereço e porta especificado e na linha 57, 58 e 59 escrevemos a requisição igual foi feito por telnet. Para executar e visualizar no console a resposta da requisição, execute o seguinte dentro do método main (utilize os devidos try/catch):
HttpClient client = new HttpClient("www.thiagovespa.com.br", 80);
System.out.println(client.getURIRawContent("/blog/"));
Para criarmos um servidor que responde à requisições desse tipo, é necessário utilizar a classe ServerSocket. Essa classe é responsável por deixar uma conexão que fica “ouvindo” por requisições de clientes em uma determinada porta. Você pode fazer igual ao descrito na linha 9 e 10 do seguinte código:
public void serve() {
ServerSocket serverSocket = null;
logger.info("Iniciando servidor no endereço: " + this.host
+ ":" + this.port);
try {
// Cria a conexão servidora
serverSocket = new ServerSocket(port, 1,
InetAddress.getByName(host));
} catch (IOException e) {
logger.log(Level.SEVERE, "Erro ao iniciar servidor!", e);
return;
}
logger.info("Conexão com o servidor aberta no endereço: " + this.host
+ ":" + this.port);
// Fica esperando pela conexão cliente
while (true) {
logger.info("Aguardando conexões...");
Socket socket = null;
InputStream input = null;
OutputStream output = null;
try {
socket = serverSocket.accept();
input = socket.getInputStream();
output = socket.getOutputStream();
// Realiza o parse da requisição recebida
String requestString = convertStreamToString(input);
logger.info("Conexão recebida. Conteúdo: " + requestString);
Request request = new Request();
request.parse(requestString);
// recupera a resposta de acordo com a requisicao
Response response = ResponseFactory.createResponse(request);
String responseString = response.respond();
logger.info("Resposta enviada. Conteúdo: " + responseString);
output.write(responseString.getBytes());
// Fecha a conexão
socket.close();
} catch (Exception e) {
logger.log(Level.SEVERE, "Erro ao executar servidor!", e);
continue;
}
}
}
Feito isso é só recuperar o input stream para pegar a requisição (linha 26) e escrever a resposta com o output stream (linha 39), igual fizemos via telnet. Fiz um projeto exemplo e na resposta escrevi o seguinte:
@Override
public String respond() {
StringBuilder sb = new StringBuilder();
// Cria primeira linha do status code, no caso sempre 200 OK
sb.append("HTTP/1.1 200 OK").append("\r\n");
// Cria os cabeçalhos
sb.append("Date: ").append(HTTP_DATE_FORMAT.format(new Date()))
.append("\r\n");
sb.append("Server: Test Server - http://www.thiagovespa.com.br")
.append("\r\n");
sb.append("Connection: Close").append("\r\n");
sb.append("Content-Type: text/html; charset=UTF-8").append("\r\n");
sb.append("\r\n");
// Agora vem o corpo em HTML
sb.append("<html><head><title>Dummy Response</title></head><body><h1>HttpServer Response</h1>");
sb.append("Method: ").append(request.getMethod()).append("<br/>");
sb.append("URI: ").append(request.getUri()).append("<br/>");
sb.append("Protocol: ").append(request.getProtocol()).append("<br/>");
sb.append("</body></html>");
return sb.toString();
}
Utilizei a porta 8091. Ao acessar a URL: http://localhost:8091/olaMundo pelo browser, o resultado é o seguinte:
Seguindo o mesmo princípio você pode criar qualquer tipo de resposta, exibir páginas html, imagens, etc., de arquivos localizados em disco, exibir conteúdo de banco de dados ou qualquer outro tipo de requisição.
O código com o projeto no eclipse está disponível aqui. Qualquer dúvida ou melhoria é só avisar.
Quebrando CAPTCHAs
CAPTCHAs (Completely Automated Public Turing test to tell Computers and Humans Apart“) são testes de Turing automatizados que tentam descobrir se você é um ser humano ou uma máquina. Em síntese os CAPTCHAs são aquelas imagenzinhas embaralhadas que aparecem quando você vai fazer um post em um blog, fazer consulta ou cadastro em alguns sites.
Por que utilizar? Ao utilizar um CAPTCHA em seu site, você evita que programas enviem spams, evita cadastros indevidos e tenta diminuir o uso informações automatizadas em outros sites. Um exemplo de uso é o meu formulário de contato.
Será que o CAPTCHA é realmente uma forma eficaz de descobrir se realmente é um ser humano que está realizando a operação? Se a gente consegue identificar o CAPTCHA, por que uma máquina não conseguiria? Um dos alunos meu perguntou se haveria uma forma de se realizar isso. A escolha foi o CAPTCHA da Receita Federal: http://www.receita.fazenda.gov.br/PessoaJuridica/CNPJ/cnpjreva/Cnpjreva_Solicitacao.asp
Por questões de segurança não irei disponibilizar o código, mas para fins acadêmicos, demonstrarei que é possível ultrapassar a barreira de alguns CAPTCHA. Alguns são fáceis, outros nem tanto.
Por exemplo, vamos ver o CAPTCHA do Facebook:
Esse CAPTCHA é monocromático, o que facilita um pouco e os ruídos existentes são uma bola de fundo e o texto torto. O do Orkut/Google só tem o texto torto:
Vamos ao da Receita Federal:
Esse CAPTCHA é muito mais complicado, há uma imagem de fundo que complica bastante, o texto está torto e são gerados vários tipos de CAPTCHAs diferentes, um com texto pontilhado, outro com um filtro esférico e esse da imagem com o texto torto em dois eixos. Vamos ao mais difícil. Fiz um programinha pra automatizar a tarefa.
O primeiro passo que eu fiz foi obter a imagem do CAPTCHA. Essa etapa é a mais fácil, o código para obter foi o seguinte:
Com essa imagem eu converto para uma BufferedImage e consigo pegar os valores de cada pixel pelo método getRGB(x,y) e posso montar minha matriz. Agora é só relembrar da época da Graduação e Mestrado: Geometria Analítica, Cálculo Numérico, Álgebra Linear, Computação Gráfica, Extração de Características, … No meu Mestrado trabalhei bastante com extração de características de imagens médicas: forma, cor, textura, identificação de cluster, … os conceitos são os mesmo, as características que mudam.
Os passos que executei para o texto torto e fonte forte foram:
- Utilizar um filtro de eliminação de ruídos. Implementei um filtro de mediana.
- Reduzir o espaço de cores da imagem.
- Utilizar uma transformação para “endireitar a imagem”. No caso utilizei duas funções cosseno. y=a*cos(b*x)+c e x=d*cos(e*f)+g. O mais difícil foi identificar os coeficientes. Fui na tentativa e erro. Ainda não está 100%.
- Dividir os caracteres. Poderia ser utilizado um k-means com k=4. Já que sempre são 4 letras.
- Extrair os caracteres e utilizar para treinamento no OCR. Realizar essas etapas com um número bom de letras. Obter o alfabeto todo seria o ideal.
- Aplicar o OCR identificando o texto.
Segue o programinha:
A primeira imagem é a original. A segunda é com o filtro de mediana aplicado. A terceira com a redução do espaço de cores. A quarta é com o “endireitamento” da imagem. E a quinta imagem é com a seleção de caracteres.
Para fontes pontilhadas o filtro de ruídos tem que ser um pouco mais suave. Ele erra bastante, mas também acerta. Cada operação dessa demora poucos milissegundos, como não há limite de tentativas e nem tempo de espera no site da Receita Federal, mesmo com vários erros a velocidade de descoberta do valor do CAPTCHA é muito baixa, poucos segundos. O mais demorado é o treinamento do OCR que é feito uma única vez. Para OCR utilizei a biblioteca JavaOCR.
Para demonstrar o “endireitamento” da imagem, que foi o que mais deu trabalho, pois foi na tentativa e erro, vou exibir uma imagem utilizando somente essa transformação, aí fica fácil entender o motivo das últimas imagens serem maiores. Eu poderia ter identificado pontos da imagem e feito interpolação de pontos para traçar uma curva, mas como é só pra conceito, fiz da forma que achei mais simples.
Criei um filtro de “efeito bandeira”
. Por isso que a imagem fica maior. Portanto, se você quer um sistema seguro, a primeira dica é, coloque um limite máximo de tentativas, obrigue uma espera de alguns minutos para a próxima tentativa e coloque algumas perguntas inteligentes além do CAPTCHA.
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:
- 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
- Abrir o Netbeans, ir em Tools, Plugins e atualiza-lo.
- Fazer o download do Perl: http://strawberry-perl.googlecode.com/files/strawberry-perl-5.12.0.1.msi e instalar
- Reiniciar o computador
- 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
- Instalar o SDK da Nokia. A partir de agora você já pode abrir o emulador da Nokia
- 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
- Tools, Java Platform, Add Platform, Java ME MIDP Platform, Next
- Verificar se encontrou o emulador da Nokia, Next
- Finish
Configurar a lib do LWUIT
- Faça o Download do LWUIT em: http://java.sun.com/javame/technology/lwuit/ no botão Download LWUIT
- Descompacte ele em uma pasta
- Vá no netbeans, Tools, Libraries
- New Library…, Library Name: LWUIT, Library Type: Class Libraries
- Add Jar/Folder, Escolher o LWUIT.jar que está na pasta lib do LWUIT, Apertar Ok
Configurar a lib do Floggy
- Faça o Download do Floggy em: http://floggy.sourceforge.net/download.html na seção Main Bundle
- Descompacte ele em uma pasta
- Vá no netbeans, Tools, Libraries
- New Library…, Library Name: Floggy, Library Type: Class Libraries
- Add Jar/Folder, Escolher o floggy-persistence-framework.jar que está na pasta lib do Floggy, Apertar Ok
- 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)
- Ir em Tools, Plugin
- Settings, Add
- Name: Checkstyle, URL: http://www.sickboy.cz/checkstyle/autoupdate/autoupdate-2.xml – OK
- Avaliable Plugins, Reload Catalog
- Selecionar Checkstyle beans plugin e library, Install
- 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
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.













