Blog do Urubatan
msgbartop
Desenvolvedor, Palestrante, Escritor, Nerd Assumido e Pai do Marcus :D
msgbarbottom

17 Feb 10 Agile Brazil 2010 – A chamada para trabalhos está aberta!

Estou de férias, e eu não ia escrever nada aqui no blog antes de voltar ao trabalho, mas isto merece o post :D
A chamada de trabalhos para o Agile Brazil 2010 esta aberta.
Se você tem algo interessante sobre Agile para falar, envie sua proposta de palestra, tutorial ou workshop por este link.

A Agile Brazil 2010 é um evento nacional organizado por representantes das principais comunidades ágeis brasileiras. Junte-se a nós submetendo trabalhos, participando do concurso do logo e divulgando o evento.

Acompanhe as novidades do @agilebrazil pelo Twitter.

O evento vai acontecer em Porto Alegre de 22 a 25 de Junho 2010.

Espero ver alguns de vocês por lá!

Tags: , , , , , , , ,

08 Jan 10 Utilizando Rake para o Build de projetos Java!

A alguns dias atrás eu li este twitt do Martin Fowler: “you don’t want a build tool which automatically downloads unresolved dependencies before cleaning out yr build output: http://bit.ly/59Rl85“, li todo o post e ele fala de forma bastante prolixa de alguns dos motivos que me fazem não gostar do Maven.

Não me levem a mal, eu já tentei utilizar ele algumas vezes, mas eu não consigo gostar de uma ferramenta que acha que sabe mais do meu projeto do que eu mesmo (ou o cliente, ou os desenvolvedores, …).
Ou pior que isto, uma ferramenta que tem a infeliz mania de tentar fazer um backup da internet antes de cada build só para verificar se tem a última versão das dependências disponível …

Como é citado no post, não acho que alguma ferramenta vá saber exatamente o que é necessário para qualquer projeto, até por que cada projeto é um projeto, e cada projeto tem suas peculiaridades, e eu simplesmente desisti todas as vezes que precisei configurar alguma destas peculiaridades no maven e voltei para o ANT.

O ANT é uma ferramenta bastante flexível, e pelo que eu tenho visto no mercado, fora alguns teimosos que preferem usar o maven mesmo passando muito mais trabalho do que o necessário, o ANT é o “defacto standard” para builds em Java, mas algumas vezes a “linguagem de script” do ANT dificulta as coisas quando se precisa realmente de um script para fazer alguma coisa durante o build, então resolvi usar Ruby para escrever os builds, ou seja, utilizar uma linguagem de scripts de verdade.

Ai pensei, como é que vou fazer para compilar meu projeto java utilizando o Rake? A linguagem de script é muito fodastica, é Ruby, eu me sinto bem programando em Ruby, mas e como compilar?

Fui perguntar ao oraculo e descobri o BuildR e o Raven que fora o fato de não utilizarem XML e sim Ruby, conseguem repetir todos os erros do Maven, eles parecem “ports do Maven para o Rake” e eu não sei por que alguem iria fazer isto, se você gosta tanto assim do Maven, use ele mesmo …

Mas do Rake eu gosto, me acostumei com ele trabalhando com o Rails, é muito fácil de automatizar tarefas relacionadas a um projeto utilizando o Rake, e não apenas o “build”, mas algumas tarefas que as vezes precisam ser automatizadas, como um merge freqüente com algum sub projeto desenvolvido em outra parte do mundo …

Isto me criou apenas um problema, como compilar, empacotar, …

Ou seja, me faziam falta as tasks básicas do ANT que eu utilizo sempre. As outras tarefas são melhor executadas na minha opinião pelo próprio Rake ou até mesmo por um script em Ruby, mas estas tarefas básicas iriam fazer falta, e para resolver isto eu criei uma classe wrapper para os comandos do JDK, que pode ser estendida depois, não é algo 100% rake, mas eu achei que ficou legal assim, se alguem não concordar e tiver idéias para melhorar estou aceitando sugestões :D

O wraper para os comandos do JDK ficou assim:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
class JavaUtil
  RAW_COMMANDS = %w{appletviewer apt extcheck idlj jar jarsigner java javac javadoc javah javap javaw javaws jconsole jdb jhat jinfo jmap jps jrunscript jstack jstat jstatd jvisualvm keytool kinit klist ktab native2ascii orbd pack200 packager policytool rmic rmid rmiregistry schemagen serialver servertool tnameserv unpack200 wsgen wsimport xjc}
 
  def initialize(jdk_home=nil)
    @commands = {}
    @jdk_home = jdk_home || ENV['java_home']
    @default_for_command = {}
    @global_default = {}
    init_commands
  end
 
  def method_missing(met,*args)
    if RAW_COMMANDS.include? met.to_s
      execute_command met, *args
    else
      super.method_missing met, *args
    end
  end
 
  def respond_to?(met)
    RAW_COMMANDS.include?(met.to_s) || super.respond_to?(met)
  end
 
  def default_parameter(param,value)
    @global_default[param] = value
  end
 
  def default_parameter_for(met,param,value)
    params = @default_for_command[met] || {}
    params[param] = value
    @default_for_command[met] = params
  end
 
  private
    def init_commands
      @jdk_bin = File.join @jdk_home , "bin"
      RAW_COMMANDS.each do |cmd|
        @commands[cmd.to_sym] = File.join @jdk_bin, cmd
      end
    end
 
    def update_or_concat_with_defaults(opts,defaults)
      defaults.each do |key,value|
        param = opts[key]
        if !param
          param = value
        else
          if param.is_a? Array
            param << value
            param.flatten!
          end
        end
        opts[key] = param
      end
    end
 
    def execute_command(cmd, *args)
      actual_command = @commands[cmd.to_sym]
      if args
        opts = {}
        opts.update args.pop if args.last.is_a? Hash
        update_or_concat_with_defaults opts, @global_default
        update_or_concat_with_defaults opts, @default_for_command[cmd.to_sym] if @default_for_command[cmd.to_sym]        
        opts.each do |key, value|
          param = value
          param = param.join File::PATH_SEPARATOR if param.is_a? Array
          actual_command << " -" << key.to_s << " "  << param
        end
        actual_command = "#{actual_command} #{args.join ' '} "
      end
      puts actual_command
      res = %x{#{actual_command}}
      puts res
      [$?,res]
    end
end

A minha idéia dos parâmetros default globais tem um pequeno problema, alguns comandos não recebem os mesmos parâmetros, mas é possível setar parâmetros padrão por comando, o que ficou legal, e deixou a compilação mais limpa …

A classe pode ser utilizada com qualquer JDK, inclusive instâncias diferentes podem utilizar JDKs diferentes para o mesmo build, basta passar o “JAVA_HOME” no construtor, por padrão a variável de ambiente é utilizada …

Mas beleza, como é que eu utilizo esta tranqueira em um Rakefile agora? bom, o meu Rakefile para o projeto de exemplo ficou assim:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
require 'lib/java_util'
@java_util = JavaUtil.new
 
task :default => :test
 
SRC_FILES = FileList.new 'src/**/*.java'
TST_FILES = FileList.new 'test/**/*.java'
CLASSPATH = FileList.new "#{File.join(ENV['TOMCAT_DIR'], 'lib').gsub /\\/,'/'}/*.jar"
 
@java_util.default_parameter_for :java, :classpath, CLASSPATH.to_a
@java_util.default_parameter_for :javac, :classpath, CLASSPATH.to_a
 
directory 'output/classes'
directory 'output/tests'
 
desc "Compile all the java files"
task :compile => ['output/classes','output/tests']  do
  @java_util.javac SRC_FILES, :d => 'output/classes'
  @java_util.javac TST_FILES, :d => 'output/tests', :classpath => ['output/classes',"#{ENV['JUNIT_DIR']}\\junit-4.4.jar"]
end
 
desc "Creates the package after compilation"
task :package => :compile do
  @java_util.jar '-cf output/target.jar -C output/classes .'
  cp 'output/target.jar', 'WebContent/WEB-INF/lib'
  @java_util.jar '-cf output/target.war -C WebContent .'
end
 
desc "Runs the tests after packaging"
task :test => :package do
  test_classes = FileList.new 'output/tests/**/*.class'
  test_classes.gsub! /output\/tests\/(.*)\.class/,'\1'
  test_classes.gsub! /\//, '.'
  @java_util.java "org.junit.runner.JUnitCore #{test_classes.join ' '}", :classpath => ['output/tests','output/target.jar',"#{ENV['JUNIT_DIR']}\\junit-4.4.jar"]
end
 
desc "Clean up all the mess we created"
task :clean do
  rm_f 'output'
  rm_t 'WebContent/WEB-INF/lib/target.jar'
end

O código dos testes não precisava ser tão complexo, eu poderia ter criado um wrapper para ele, a mesma coisa para a criação do jar, poderia até mesmo ter utilizado o “rubyzip” para deixar mais bonitinho, mas a idéia por enquanto é ser bem simples.

Estou utilizando este build em um projeto, se engrenar provavelmente a biblioteca vá crescendo, mas acho que por agora já serve para começar a brincar e ver o que vocês acham da idéia.
A classe “JavaUtil” precisa ser mais testável, mas isto tornou ela complexa demais para o exemplo deste post, se eu convencer o resto da equipe a continuar usando esta solução vou melhorando ela aos poucos :D

Acho que vou separar a montagem do comando e a execução do mesmo, ou transformar cada comando em uma classe para facilitar a expansão da biblioteca e tornar mais testável, ou até mesmo as duas coisas.
No momento a classe não é nada testável, mas já esta divertida e o meu bluid diminuiu muitas linhas depois que eu converti ele de ANT para Rake utilizando esta lib :D

PS.: quem quiser pegar o projeto de testes para brincar, só para olhar ou até mesmo para implementar algumas melhorias, ele esta publicado no github. Se implementarem alguma melhoria, não esqueçam de enviar um pull request para que eu possa fazer o merge das alterações :D

Tags: , , , ,

24 Sep 09 Software Auto Identificável – Self Identifying Software

2identify_yourself_logo3333
esta imagem foi encontrada na web usando o images.google.com e eu achei que tinha a ver com o post

Eu não conhecia o conceito até ver este twit do CV falando deste post sobre Self Identifying Software. E lendo o post percebi que já passei e algumas vezes ainda passo pelo mesmo problema: Identificar qual versão do software esta instalada em um servidor, ou em que versão do sofware algum bug apareceu ou aconteceu ou acontece …

Bom, eu curti a idéia e fiquei pensando em como implementar isto, pelo menos em projetos Java, disto sairam estes “code snippets” abaixo …
Bom, normalmente trabalho com o ANT para fazer o build de projetos Java, e tenho utilizado o Subversion (sim, eu conheço o GIT e gosto dele, mas no momento não vai rolar no trampo, mas uso para projetos pessoais :D )
Então, fui a página do subversion e baixei o SVNANT, desenvolvido pelo pessoal do subclipse, e integrei ele no meu build assim:

1
2
3
4
5
6
7
8
9
10
        <path id="svn_tasks">
		<fileset dir="${directory_you_unzipped_the_svnant_package}" includes="svn*.jar">
		</fileset>
	</path>
	<taskdef classpathref="svn_tasks" resource="org/tigris/subversion/svnant/svnantlib.xml" />
	<target name="_setup_svn_info">
		<svn failonerror="false" javahl="true" svnkit="false">
			<info target="${basedir}" verbose="true"/>
		</svn>
	</target>

Depois disto, em qualquer parte do build em que você for criar um .jar, .war ou qualquer tipo de pacote java, basta fazer algo parecido com isto:

1
2
3
4
5
6
7
8
9
        <target name="build_jar" depends="_setup_svn_info,compile">
		<jar destfile="${dist.dir}/${jar.name}">
			<fileset dir="${basedir}/bin" includes="*.*" />
			<manifest>
				<attribute name="SVN-URL" value="${svn.info.url}" />
				<attribute name="SVN-REV" value="${svn.info.rev}" />
			</manifest>
		</jar>
        </target>

Claro que o importante é o depends e o manifest, o resto vai depender do seu build, isto não é nem um exemplo real, escrevi direto aqui no blog para dar a idéia, então se tiver algum problema com o código me avisem nos comentários :D

Mas isto não é útil se você não conseguir ler o MANIFEST.MF do .jar onde a sua classe se encontra, então estou colocando aqui também um exemplo de código para isto, mas lembre-se de alterar o nome da classe para cada pacote, caso contrário você nunca saberá de qual pacote a classe esta sendo carregada :D

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package blog.urubatan;
 
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.jar.Manifest;
 
public class ExemploDoUrubatan {
	private Manifest manifest;
 
	private void initManifest() throws URISyntaxException,
			FileNotFoundException, IOException {
		Class<?> clazz = getClass();
		URL classContainer = clazz.getProtectionDomain().getCodeSource()
				.getLocation();
		File manifestContainer = new File(classContainer.toURI());
		File metaInf = new File(manifestContainer, "META-INF");
		File manifestFile = new File(metaInf, "MANIFEST.MF");
		manifest = new Manifest(new FileInputStream(manifestFile));
 
	}
 
	public ExemploDoUrubatan() throws URISyntaxException,
			FileNotFoundException, IOException {
		initManifest();
	}
 
	public String getSvnUrl() {
		return manifest.getMainAttributes().getValue("SVN-URL");
	}
 
	public String getSvnRevision() {
		return manifest.getMainAttributes().getValue("SVN-REV");
	}
 
	public static void main(String[] args) throws FileNotFoundException,
			URISyntaxException, IOException {
		ExemploDoUrubatan ex = new ExemploDoUrubatan();
		System.out.println(ex.getSvnUrl());
		System.out.println(ex.getSvnRevision());
	}
}

Se for a versão de um arquivo .war o código pode ser colocado em um servlet com uma URL conhecida, ou em um listener que vai guardar esta informação no servlet context para ser impresso depois por uma URL conhecida …
Se o servlet for a opção selecionada, o código ficaria parecido com isto:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package blog.urubatan;
 
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
public class ServletExample extends HttpServlet {
	private static final long serialVersionUID = 1L;
 
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		super.doPost(req, resp);
	}
 
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		String warRoot = getServletContext().getRealPath(".");
		File manifestContainer = new File(warRoot);
		File metaInf = new File(manifestContainer, "META-INF");
		File manifestFile = new File(metaInf, "MANIFEST.MF");
		Manifest manifest = new Manifest(new FileInputStream(manifestFile));
		PrintWriter writer = resp.getWriter();
		Attributes mainAttributes = manifest.getMainAttributes();
		String svnUrl = mainAttributes.getValue("SVN-URL");
		String svnRev = mainAttributes.getValue("SVN-REV");
		writer.format("URL: %s\nRev:%s\n", svnUrl, svnRev);
	}
 
}

Com isto, pelo menos para projetos java, já cobrimos duas das situações mais comuns, que são saber a versão de uma API e saber a versão de uma aplicação WEB.
Com isto já é possível verificar o deploy de aplicações durante o build se o script for um pouco mais inteligente, o pessoal de testes tem condições de dizer exatamente qual foi a build que gerou o problema, é possível construir um “dashboard” com a versão de tudo que é utilizado no sistema, facilitando bastante a identificação de onde o problema ocorre, e principalmente, no caso de clusters, permitindo que seja verificada a versão em cada um dos nós de uma forma fácil …

Agora no caso do Rails, eu ainda não consegui decidir qual a melhor abordagem para isto …
criar um arquivo com estes meta dados dentro do diretório config, atualizar este arquivo por uma task rake toda vez que for executar um deploy via capistrano e criar um controller para informar a versão?
As gems já tem um mecanismo de versionamento, seria só atualizar a versão da gem a cada build, coisa que pode ser feita até com keywork expansion, ou utilizando o mesmo esquema do rake mencionado antes.
Bom, vou pensar mais nisto, derepente rola até criar um plugin para aplicações rails pra facilitar a vida :D
O que vocês acham?

Tags: , , , ,

16 Sep 09 Não seja repetitivo, nunca comente o que o seu código faz

Eu sei que já falei sobre comentários antes, mas acho que a abordagem não agradou muito, a maior parte das pessoas leu só o título do post e não prestou atenção no texto, então vamos tentar uma abordagem diferente.
Este post é o primeiro de uma série de 2, o próximo post vai dizer que é necessário comentar o código, mas com comentários decentes, então, sem gritaria por aqui por enquanto, ok?
Mas vamos ao que interessa …
Na minha opinião, qualquer programador Java, ou até mesmo, qualquer programador, que colocar os olhos no código abaixo, vai entender quase que instantaneamente o que ele faz, se alguem não concordar com isto, avise por favor …

1
2
3
4
5
6
new EmailMessage()
    .from("exemplo@urubatan.com.br")
    .to("gerente@empresa.com")
    .withSubject("Aprovação de processo")
    .withBody("Descrição bastante detalhada do que precisa ser aprovado")
    .send();

(sim, copiei o exemplo do blog do GC :D )
Então, eu acredito que se alguem quiser colocar um comentário neste código dizendo algo do tipo:

  • Envia email
  • Cria uma mensagem de email, configura propriedades e depois envia

Vai estar simplesmente sendo repetitivo, e poluindo o código com comentários inúteis, isto seria dizer o que o código faz, e se você comenta o que o seu código faz você é sim um perdedor que gosta de jogar trabalho no lixo!
Ahh, mas e se meu código não é assim tão claro? E se meu código é parecido com isto:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// create some properties and get the default Session
Properties props = new Properties();
props.put("mail.smtp.host", _smtpHost);
Session session = Session.getDefaultInstance(props, null);
 
// create a message
Address replyToList[] = { new InternetAddress(replyTo) };
Message newMessage = new MimeMessage(session);
if (_fromName != null)
    newMessage.setFrom(new InternetAddress(from,
        _fromName + " on behalf of " + replyTo));
else
    newMessage.setFrom(new InternetAddress(from));
    newMessage.setReplyTo(replyToList);
    newMessage.setRecipients(Message.RecipientType.BCC, _toList);
    newMessage.setSubject(subject);
    newMessage.setSentDate(sentDate);
 
// send newMessage
Transport transport = session.getTransport(SMTP_MAIL);
transport.connect(_smtpHost, _user, _password);
transport.sendMessage(newMessage, _toList);

Bom, se o seu código é assim, então você precisa estudar um pouco de refactoring :D
Ahh, mas estou alterando uma parte da aplicação com muito código legado …
Bom, você deveria utilizar pelo menos alguns “extract method” para facilitar um pouco a leitura, e não comentar o que o código faz.

Imaginem a seguinte cena:
Você esta caminhando na rua e entra em uma loja, no momento em que você entra na loja, vê uma placa escrito: Roupas masculinas
Dois passos adiante, um vendedor chega e diz: Senhor, aqui o senhor vai encontrar roupas masculinas
Mais alguns passos e outro vendedor: Vendemos roupas masculinas aqui senhor.
E mais outra placa dizendo: Aqui roupas masculinas

Se você ainda estiver na loja e não bater no próximo que lhe visar que ali são vendidas roupas masculinas, no mínimo acabou de ocorrer um desperdício absurdo de esforço para informar exatamente a mesma coisa.
E este caso do email não é um dos mais comuns, o motivo deste post é que em muitos lugares eu vejo código parecido com:

1
2
3
4
5
6
/**
 * Set's the active property
 */
public void setActive(boolean active) {
   this.active = active;
}

(Isto não é uma critica a ninguém especifico e a todos os que já escreveram código assim, não foi uma nem duas vezes que vi isto por ai …)
um método de nome “setActive” com o comentário “Set’s the active property” é no mínimo redundância, e desperdício de tempo.
Então, eu não estou dizendo, nunca comentem o seu código, mas estou dizendo, se você precisa dizer o que o seu código faz, o seu código tem problemas, mas comentários são úteis, principalmente em interfaces públicas se você estiver informando por que ou como o código faz o que faz …
Mas tenha como regra, é proibido um comentário dizendo o que o código faz, pois ele é um sinal de que o código esta muito ruim!!

Ahh, e só para terminar, a biblioteca que permite aquele código de envio de emails bonitinho é a “Fluent Mail API” e o nome desta “técnica” é “Fluent Interfaces”, uma “técnica” bastante utilizada por quem trabalha com “Domain Driven Design”, e DDD faz Orientação a Objetos realmente mais divertida e mais útil, vou falar mais sobre isto em breve :D .

Tags: , , , , ,

05 Jul 09 Eclipse 3.5 Galileo – Mais rápido, menor foot print e mais “cool” do que no ano passado!

Galileo is Here
É, novamente chegou aquela época do ano, em que o pessoal da Eclipse Foundation libera mais um “Release Train”, ou seja, uma nova versão de diversos projetos simultaneamente e compatível entre sí.
Isto é melhor ainda para quem lembra dos tempos pré Calisto, que foi o primeiro “Release Train”, naqueles tempos longínquos era necessário baixar cada um dos plugins na mão, e torcer para ter pego uma versão compatível, o que na maioria das vezes não era verdade …
Utilizar o eclipse, principalmente com o WTP era uma tarefa apenas para os mais fortes e mais preparados, e Darwin era quem ditava as regras da comunidade.
Existiam projetos paralelos de ambientes para desenvolver WEB com o eclipse que tentavam facilitar a vida dos menos preparados, mas estes não tinham vez quando se falava em qualquer outro projeto da Eclipse Foundation fora o JDT.
Mas estes tempos acabaram, os Release Trains possibilitam o acesso ao poder do eclipse para todos os interessados, e não apenas aos iniciados.
E este post cheio de firulas e histórias sem nexo foi escrito para falar um pouco mais do Release Train de 2009, o Galileo; que diferente de seus antecessores Callisto, Europa e Ganymede não é o nome de uma das luas de Jupiter, mas o nome do grupo de luas de Júpiter que inclui as 3 anteriormente citadas e também Io, e é também o nome do cientista que em 1609 oficialmente descobriu as 4 maiores luas deste planeta.
Mas alem de ser uma das luas de Júpiter, é também o nome do Release Train do Eclipse em 2009 que inclui os seguintes projetos:

Project Name Version Project Summary Download
Acceleo Acceleo 0.8.0 Download
Accessibility Tools Framework 0.7.0 Download
ATL – Atlas Transformation Language 3.0.0 Download
Buckminster Component Assembly Download
Business Intelligence and Reporting Tools (BIRT) Download
C/C++ Development Tooling (CDT) 6.0 Download
CDO Model Repository 2.0.0 Download
Dali Java Persistence Tools 2.2 Download
Data Tools Platform 1.7 (Galileo) Download
Dynamic Languages Toolkit 1.0 Download
Eclipse Communication Framework ECF 3.0 Download
Eclipse Modeling Framework (EMF) 2.5.0 Download
Eclipse Packaging Project 1.1.0 Download
Eclipse Platform 3.5 Download
Eclipse Project 3.5.0 Download
Eclipse Web Tools Platform Project WTP 3.1.0 (Galileo) Download
EclipseLink Project 1.1.2 Download
EMF Compare Download
EMF Teneo Model Relational Mapping 1.1.0
Equinox 3.5 Download
GEF – Graphical Editor Framework 3.5.0 Download
Graphical Modeling Framework 2.2.0 Download
Java Workflow Tooling JWT 0.6 Download
JDT – Java development tools Download
M2T JET (Java Emitter Templates) – aka JET2 M2T JET 1.0.0 (Galileo) Download
MDT OCL (Object Constraint Language) 1.3 (Galileo) Download
MDT UML2 Tools 0.9.0 (Galileo) Download
MDT XSD (XML Schema Definition) 2.5.0 Download
MDT-UML2 3.0.0 Download
Memory Analyzer 0.8.0 Download
Mobile Tools for Java Download
Model Development Tools (MDT) Galileo Download
Model To Text (M2T) Galileo (xpand 0.7, acceleo 0.8, jet 1.0) Download
Model-to-Model Transformation (M2M) Galileo Simultaneous Release Download
Monitoring Tools 4.6.0 Download
Mylyn 3.2 Download
Net4j Signalling Platform 2.0.0 Download
PHP Development Tools 2.1.0 Download
Rich Ajax Platform 1.2 Download
Riena Platform Project 1.1.0. Download
SCA Tools 2.0.0 Download
SOA Tools 2.0 Download
Source Editing 3.1.0 (Galileo) Download
Subversive – SVN Team Provider Download
Swordfish 0.9.0 Download
Target Management 3.1 Download
Test and Performance Tools Platform Project 4.5.3 Download
Testing Tools TPTP v4.6 Download
Textual Modeling Framework org.eclipse.xtext Download
Tools for mobile Linux 0.3 Download
TPTP Platform TPTP v4.6 Download
Tracing & Profiling Tools TPTP v4.6.0 Download

Bom, se você não dormiu até chegar aqui, vamos ao que interessa, o que tem de bom, e de diferente nesta versão do eclipse, fora um monte de números de versões novas.
os meus comentários são referentes ao Download “for J2EE Developers”, ou seja, com o WTP já instalado.

A primeira coisa que notei foi que esta versão do eclipse, não passou de 200M de memória em nenhum momento, tenho utilizado ele o dia inteiro, e a ocupação de memória fica em média entre 130M e 160M, bem melhor que o Ganymede que estava sempre entre 300M e 600M. Isto por sí só já é uma grande vantagem, o Eclipse esta bem menos pesado, e todas as operações estão com um tempo de resposta perceptível bem menor. Não sei se o tempo real esta menos, mas isto não me importa muito mesmo :D
Uma coisa que não gostei, é que aquela perspectiva podre “Java EE” é a perspectiva padrão, eu sempre prefiro utilizar a perspectiva Java como padrão.
O Suporte ao ANT continua fraco, se em um projeto existirem muitos arquivos build.xml, em algum momento o editor vai entrar em coma e só vai voltar a funcionar depois de reiniciar a IDE, mas o auto complete esta mais inteligente e mais rápido …
Uma coisa que achei muito legal é que o eclipse agora reconhece os XMLs gerados por um output do JUnit Report do ANT e abre ele na mesma view dos resultados do JUnit executados pela IDE, o que facilita muito a visualização :D
A versão nova do gerenciador de plugins também esta bem legal, ficou mais intuitivo para os novos usuários …
Mas o eclipse ainda não vem com suporte nativo ao subversion, o plugin esta no repositório do Galileo, mas não vem instalado, quando você instala o eclipse, só tem suporte a CVS o que é sofrível. E mesmo assim, só existe suporte “oficial” para estes dois SCMs, se quiser usar GIT vai ter que correr atrás.
Mas nem tudo são problemas, a nova view de “Problems” com as coisas agrupadas ficou bem legal.
Um recurso novo espetacular do editor, é a possibilidade de selecionar blocos, sempre senti falta disto no Eclipse :D
O Code completion do editor Java esta mais rápido, ou pelo menos parece mais rápido, e pode ser por que criei um workspace novo, mas parou de ocorrer um erro muito chato do Mylyn antes de apresentar os proposals para o code completion que me enchia o saco na versão anterior, mas acontecia só uma ou duas vezes por dia …
Outra coisa legal é que agora quando se segura o “Control” com o mouse sobre um método ou classe, antes sempre era aberta a implementação, agora o Eclipse pergunta se você quer ver a implementação ou a definição do método.
Achei muito extranho o icone novo do eclipse, principalmente por que o icone da aplicação não mudou, mas o icone no task bar do windows mudou, parecem duas aplicações diferentes :D
(E sim, antes que alguem comente, aqui no trampo sou obrigado a usar windows)

O suporte a Java ME ainda é bem mais fraco que o do NetBeans, mas o eclipse tem suporte a desenvolvimento em C++ para dispositivos móveis (não cheguei a testar) o NetBeans não tem …
O suporte a linguagens dinâmicas também melhorou, pelo menos o suporte a Ruby melhorou, mas ainda não existe suporte direto ao Rails …
O editor de C++ esta mais rápido, mas ainda com um code completion bem fraco e um suporte quase inexistente a refactorings, mas o “quase” já faz isto ser muito melhor do que no Visual Studio.
Ocorreram também diversas mudanças estruturais no Eclipse, mas como eu sou apenas mais um usuário da ferramenta, vou deixar este tipo de comentário para quem realmente entende.

Bom, se você teve paciência de ler até aqui é por que esta interessado no Eclipse (ou não tinha nada melhor para fazer :D ), então esta na hora de acessar o site do Eclipse e baixar o galileo.
Nesta página existem diversas opções, uma delas vai te deixar feliz, mas se você é um usuário “Hard Core” das antigas, e realmente gosta de passar trabalho, baixe o Eclipse Classic no final da página e monte o seu ambiente com os plugins que estiver com vontade :D
Se você não conseguir se decidir qual é a versão certa para você, basta acessar esta página, que diz o que esta incluído em cada um dos pacotes disponíveis para download.
Para facilitar a sua vida, copiei a tabela com os downloads e coloquei aqui :D


Tools for Java developers creating Java EE and Web applications, including a Java IDE, tools for Java EE, JPA, JSF, Mylyn and others. More…

Downloads: 202,591

Windows

Mac OS X (Carbon)

Mac OS X (Cocoa)
Linux 32bit
Linux 64bit

The essential tools for any Java developer, including a Java IDE, a CVS client, XML Editor and Mylyn. More…

Downloads: 74,402

Windows

Mac OS X (Carbon)

Mac OS X (Cocoa)
Linux 32bit
Linux 64bit

Tools for PHP developers creating Web applications, including PHP Development Tools (PDT), Web Tools Platform, Mylyn and others. More…

Downloads: 47,243

Windows

Mac OS X (Carbon)

Mac OS X (Cocoa)
Linux 32bit
Linux 64bit

An IDE for C/C++ developers with Mylyn integration. More…

Downloads: 36,326

Windows

Mac OS X (Carbon)

Mac OS X (Cocoa)
Linux 32bit
Linux 64bit

A complete set of tools for developers who want to create Eclipse plug-ins or Rich Client Applications. It includes a complete SDK, developer tools and source code, plus Mylyn, an XML editor and the Eclipse Communication Framework. More…

Downloads: 12,642

Windows

Mac OS X (Carbon)

Mac OS X (Cocoa)
Linux 32bit
Linux 64bit

This modeling package contains a collection of Eclipse Modeling Project components, including EMF, GMF, MDT XSD/OCL/UML2, M2M, M2T, and EMFT elements. It includes a complete SDK, developer tools and source code. Note that the Modeling package includes some incubating components, as indicated by feature numbers less than 1.0.0 on the feature list. More…

Downloads: 10,763

Windows

Mac OS X (Carbon)

Mac OS X (Cocoa)
Linux 32bit
Linux 64bit

JEE tools and BIRT reporting tool for Java developers to create JEE and Web applications that also have reporting needs. More…

Downloads: 9,907

Windows

Mac OS X (Carbon)

Mac OS X (Cocoa)
Linux 32bit
Linux 64bit

Pulsar is a tools platform for Mobile Java Developers. It includes the Eclipse Platform, Java Development Tools (JDT), Mobile Tools for Java (MTJ), Mylyn and Plugin Development Environment (PDE). Pulsar also makes it easy to download SDK from different handset manufacturers. More…

Downloads: 5,361

Windows

Mac OS X (Carbon)

Mac OS X (Cocoa)
Linux 32bit
Linux 64bit

The classic Eclipse download: the Eclipse Platform, Java Development Tools, and Plug-in Development Environment, including source and both user and programmer documentation. Please look also at the Eclipse Project download page. More…

Windows

Mac OS X (Carbon)
Mac OS X (Cocoa)

Linux 32bit
Linux 64bit

Bom, vou ficando por aqui, este post foi escrito para participar do Blogathon, e tentar ganhar uma jaqueta do Eclipse :D
Acho difícil um post em português ganhar, mas pelo menos uma camiseta acho que rola :D

Tags: , ,

13 May 09 Java tem espelhos, e o mago deve saber jogar com eles (Básico da Reflexão)

Ok, o título deste post ficou meio estranho, mas como muita gente diz que isto é magia negra mesmo, então até que o título não esta tão ruim :D
Uma coisa que eu vejo bastante por ai, e não é de hoje, é que grande parte dos programadores Java não faz idéia do que seja Reflection, e normalmente tem medo de escrever, ou até mesmo de ler código “complicado”.
Não vou dizer que reflection é simples, mas é um recurso extremamente poderoso do Java que todo programador Java deveria conhecer.

O que é Reflection

Reflection em java, é como o nome diz, a possibilidade de programaticamente, visualizar um reflexo de um objeto ou uma classe, e como em um espelho, é possível também distorcer um pouco esta imagem quando necessário.
Como no reflexo em um espelho, o que você visualiza, não é o objeto real, apenas um reflexo deste, mas como na física, você pode deduzir como interagir com o objeto real, utilizando o seu reflexo.

Quando eu escrevi isto, lembrei de uma cena de um filme muito velho, acho que era “fúria de titâs” ou algo assim, onde alguem utilizava o reflexo da medusa em um escudo para lutar com ela sem se transformar em pedra.

Mas voltando ao assunto, reflection, é a possibilidade, de em tempo de execução, diversas informações sobre um objeto qualquer, incluindo mas não se limitando a seguinte lista:

  • Qual é a classe de um objeto
  • Quais métodos públicos a classe possui
  • Quais métodos foram declarados na classe (incluindo os privados)
  • Quais interfaces a classe implementa
  • Qual classe a classe do objeto estende
  • Quais anotações foram colocadas em uma classe
  • Quais anotações foram colocadas em um método
  • Quais anotações foram colocadas em um atributo
  • Quais anotações foram colocadas em um parâmetro de um método
  • Quais os tipos dos parâmetros de um método
  • Qual o tipo dos atributos de uma classe
  • Qual o tipo de retorno de um método

Via reflexão também é possível por exemplo, executar as seguintes ações em um objeto de uma classe que não existia no momento em que o código foi desenvolvido (um plugin por exemplo):

  • Instanciar um objeto
  • Chamar um método passando parâmetros ou não
  • Ler o valor de atributos privados de um objeto
  • Criar um clone de um objeto copiando o estado do mesmo
  • Chamar diretamente métodos privados de um objeto
  • Chamar métodos estáticos de uma classe
  • Ler atributos estáticos de uma classe

Claro que estes são só exemplos, a API de reflection adiciona muito mais flexibilidade do que isto, principalmente quando combinada com algum framework de AOP ou com a API de criação de Proxies disponível no próprio Java.
Mas para fazer tudo isto, é necessário conhecer algumas classes que a maior parte dos programadores Java não se preocupam em conhecer.
Só um detalhe antes de apresentar as novas classes, apenas combinando a API de reflection com a API de Proxies e o suporte a annotations do Java 5 é possível implementar todos os recursos do EJB3 por exemplo.
Agora vamos aprender a usar espelhos para fazer mágica :D

  • java.lang.Class – Esta é a classe que representa uma classe, todos os objetos tem um método “getClass” que retorna um objeto do tipo java.lang.Class, a partir de um objeto deste tipo, é possível obter diversas informações sobre uma classe, este é o ponto de entrada para o mundo dos espelhos, exatamente como aquele espelho do Alice no pais das maravilhas, mas sem o perigo de ficar preso por la como aconteceu com ela
  • java.lang.reflect.Field – Esta é a classe que representa um atributo de uma classe, objetos deste tipo nos permitem saber por exemplo, o nome dos campos de uma classe, e até mesmo ler o valor destes atributos
  • java.lang.reflect.Method – Objetos deste tipo representam métodos de uma classe, é possível utilizar estes objetos para chamar métodos passando ou não parâmetros para eles, mesmo que estes métodos sejam privados
  • java.lang.reflect.Modifier – Esta classe permite saber se um método ou atributo é privado ou publico, se ele é estático, ou seja, quais os modificadores de acesso foram utilizados na declaração do método, atributo ou classe
  • java.lang.reflect.Array – Esta classe representa um array, com objetos deste tipo é possível acessar todos os elementos de um array por exemplo
  • java.lang.reflect.Constructor – Esta classe representa um construtor de uma classe qualquer, uma classe pode ter diversos contrutores, e com referências para estes contrutores podemos saber quais os parâmetros necessários para instanciar uma objeto, ou até mesmo instanciar o objeto realmente
  • java.lang.reflect.AnnotatedElement – esta interface permite saber quais as anotações presentes em uma declaração, ela é implementada por Class, Method e Field por exemplo
  • Package java.lang.reflect – Antes de continuar lendo, por favor de uma olhada em quais as outras classes disponíveis no pacote responsável pela criação de espelhos e também pela distorção dos reflexos nestes espelhos no Java

Agora um exemplo básico, por que acredito que vocês não conseguiram entender muita coisa até aqui, mas eu prometo que depois de um exemplo as coisas vão ficar um pouco mais claras.

Este exemplo, razoavelmente simples, vai listar todos os métodos e atributos públicos em uma classe.
Para o exemplo se tornar um pouco mais divertido, o nome da classe deve ser passado como parâmetro, isto também faz você poder listar uma classe que não existia quando o programa foi compilado.

test/List.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 
package test;
 
import java.lang.reflect.*;
 
public class List {
        public static void main(String[] args) throws Exception{
                if(args.length!=1)
                        throw new Exception("Voce precisa informar o nome da classe como unico parametro");
                Class<?> clazz = Class.forName(args[0]);
                printClassInformation(clazz);
                printClassAttributes(clazz);
                printClassMethods(clazz);
        }
        public static void printClassInformation(Class<?> clazz) throws Exception {
                System.out.println("Class Name: " + clazz.getName());
        }
        public static void printClassAttributes(Class<?> clazz) throws Exception {
                for(Field f : clazz.getDeclaredFields()){
                        System.out.format("\t--Private Attribute Name: %s, Attribute Type: %s\n",f.getName(),f.getType().getName());
                }
        }
        public static void printClassMethods(Class<?> clazz) throws Exception {
                for(Method m : clazz.getMethods()){
                        System.out.format("\tMethod Name: %s, Return Type: %s, Parameter Types: %s\n",m.getName(),m.getReturnType().getName(),m.getParameterTypes().toString());
                }
        }
}

Compile este exemplo, e execute passando por exemplo “java.lang.Class” como parâmetro e você vai ter um exemplo básico do funcionamento da API de Reflection.
Você pode também criar outra classe, empacotar ela em um arquivo .jar, adicionar este jar no classpath e executar este exemplo passando o nome da sua nova classe como parâmetro.

Claro que este é um exemplo extremamente básico, com um código que se não fosse pelo parâmetro passado para algumas classes, poderia ser executado até no Java 1.2, ou seja, a API de reflexão não é nova, é apenas sub utilizada pelo programador de nível médio.
Ahh, mas saber isto vai fazer com que eu seja um expert em java?
Claro que não! Mas não saber isto, com certeza te impede de ser um :D

test/Call.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 
package test;
 
import java.lang.reflect.*;
 
public class Call {
        public static void main(String[] args) throws Exception {
                Class<?> clazz = Class.forName(args[0]);
                Method m = clazz.getMethod(args[1]);
                Object instance = clazz.newInstance();
                Object result = m.invoke(instance);
                System.out.println(result);
        }
}

Este é outro exemplo bastante simples, apenas para demonstrar algumas possibilidades, este exemplo bastante simples, chama um método sem parâmetros em uma classe qualquer que tenha um construtor padrão.
Para chamar métodos estáticos, seria necessária uma pequena alteração, o parâmetro passado para o método “invoke” da classe Method, é a instancia do objeto onde o método deve ser chamado, para métodos estáticos, esta instância é substituida pela classe que possui o método estático.
E o construtor padrão é necessário, por que precisamos de uma instância da classe para invocar o método, se a classe não possuir um construtor padrão, precisaremos passar parâmetros para o construtor, o que iria complicar bastante o exemplo, e a idéia aqui é só mostrar algumas possibilidades, e não complicar mais ainda a vida de vocês.
Mas como funciona o exemplo?
Tente compilar o exemplo, e executar ele passando os parâmetros:
java.lang.Object hashCode
ou
java.lang.Object toString
ou
QualquerNomeDeClasse nomeDeUmMétodoSemParâmetrosDestaClasse
e pronto, método executado.

Ai você vai pensar agora: Mas é muito mais fácil eu escrever direto “System.out.println(new Object().hashCode())” no meu código.
Claro que é, mas para isto você precisaria saber que o método que seria executado era o hashCode de uma nova instância de Object.
A idéia da API de reflection é obter informações em tempo de execução, é possibilitar um pouco de méta programação no Java.

Imagine só, criar um proxy para uma interface que garante que todos os métodos executados, caso tenham a anotação @Transactional, serão executados dentro do contexto de uma transação.
Isto é meta programação, isto é manter a mente um pouco mais aberta do que o programador médio.

Outra possível pergunta: Tu não vai ser expulso do clubinho por que esta revelando os segredos, como aconteceu com o Mister M?
Resposta: Claro que não, isto não é segredo nenhum, tu só não tinha aprendido antes por que não parou para estudar. Se você fosse um pouco mais preguiçoso, como eu, você já teria parado para estudar uma forma de trabalhar menos com as ferramentas que você tem na mão, e se você é um programador, meta programação, é uma forma de fazer mais trabalhando menos.

Mais uma pergunta: Por que ninguem me contou isto antes? explicando assim até parece fácil!
Resposta: Provavelmente achavam que tu é burro demais para entender, agora tu pode provar que isto não é verdade. E não se engane, não é tão simples assim, código usando reflexão pode ficar bastante complicado, eu só mostrei uns exemplos bem básicos.

A API de Proxies eu vou deixar como assunto para um próximo post, minha imagina imaginação esta meio fraca hoje, estou de saco cheio de assistir esta aula maluca que eu não to nem prestando atenção, acho que vou pra casa já :D

Se vocês tiverem idéias de mais exemplos que vocês querem ver como pode ser feito com reflexão, ou se tiverem perguntas sobre reflexão em java, por favor sintam-se a vontade de registrar as perguntas, dúvidas e sugestões aqui nos comentários do blog, vou tentar responder todas as perguntas :D
E como sempre, se você gostou deste post, indique para seus amigos, e coloque um link no seu blog :D

Acho que daqui a uns dias eu escrevo mais sobre reflection, mas vou tentar utilizar uns exemplos mais complexos, se tiverem sugestões para o próximo post, é só deixar nos comentários.

Tags: , , ,

27 Mar 09 JustJava’09 – Chamadas de Trabalhos – Inscrições Abertas!

E seguindo com a temporada de eventos 2009 recem aberta, como falei do Agileweekend e do FISL 10. Agora é a vez do Just Java 2009, um dos maiores e mais tradicionais eventos sobre Java do brasil abrir a chamada de trabalhos e as inscrições para participantes.
O Just Java foi o primeiro evento sobre java que assisti ainda em 2002, e foi o segundo em que palestrei, acho que em 2003 se não me engano.
O evento sempre foi muito bom, e la eu conheci muitos dos que eu considero como meus amigos hoje, e continuo conversando via internet. Foi la que encontrei pela primeira vez pessoalmente o pessoal do GUJ (um dos melhores, se não o melhor, forum sobre java em protugues).
Resumindo a história, o Just Java, além de ser um dos maiores eventos sobre java, é também um dos melhores, se não o melhor evento sobre Java do Brasil.
Recomendo a participação a todos os que tiverem a oportunidade.
Este ano não vou palestrar la por que meu filho esta quase nascendo e não quero viajar muito (Já vou participar do Web Days, daqui a uns dias escrevo um post sobre isto, assim que o evento tiver um local definido).
Uma outra coisa espetacular do Just Java é que o pessoal do Sou Java sempre tenta deixar espaço para quem esta começando a palestrar, quem quer começar a mostrar seu trabalho, eles sempre deixam alguns espaços para quem nunca palestrou no evento, e as vezes quem nunca palestrou em lugar algum, então, se você conhece bastante sobre algum assunto, ou se esta estudando muito sobre um determinado assunto, envie uma proposta de palestra, é sempre melhor alguem que recem aprendeu fazer uma palestra para iniciantes, por que quem ja usa uma tecnologia a muito tempo normalmente não tem paciência para falar das cosias mais básicas, e as vezes nem lembra mais pois muita coisa se tornou automática.
Então se você acha que tem do que falar, tente falar, no máximo a proposta não vai ser aceita, não é nada pessoal, é que eles realmente recebem muitas propostas, e se a sua proposta for aceita, no máximo você vai ficar conhecido por uma boa parte da comunidade Java do Brasil.

Só para finalizar: participe do Just Java 2009, seja assistindo as palestras ou fazendo uma palestra.
O evento vai ocorrer de 15 a 17 de setembro no SENAC Santo Amaro em SP.

PS.: Este post esta sem o logo do evento por que no site o logo esta dentro de um Flash. Se alguem do Sou Java vir este post me passe por favor o logo para eu poder atualizar o post :D

Tags: , ,

10 Feb 09 Sun Certified Developer for Java Web Services 5 – Passei na prova Beta

A algum tempo atrás eu disse que nunca mais iria fazer uma prova de certificação Beta, mas como eu disse neste post, no final do ano passado eu fiz a versão Beta da nova certificação da SUN “Sun Certified Developer for Java Web Services 5″.
Uma das coisas chatas de uma prova beta é que leva mais de 6 semanas para darem o resultado da prova, e hoje fui acessar o site da prometric para ver o resultado (como tenho feito uma vez por semana a algum tempo) e eu passei na prova :D

Isto quer dizer que eu tenho mais algumas letras sem muita utilidade para enfeitar o meu currículo (SCDJWS) :D

Eu sei que certificações não provam nada, ainda mais com provas difíceis como esta, em que eu esqueci da prova e não estudei nada (o que prova que com o conhecimento adquirido no trabalho é possível passar em uma prova de certificação), mas mesmo assim, foi uma prova que levei 3 horas para fazer, então merece pelo menos um post no blog de comemoração :D .

Tags: ,

19 Jan 09 Profiglacy – Nunca foi tão fácil escrever uma UI com Swing (Graças ao JRuby)

O nome é complicado mesmo, o nome da biblioteca é “Profiglacy“. O nome da biblioteca veio de um SPAM recebido pelo Zed Shaw e ele utiliza esta biblioteca para escrever um programa de nome iHate, que é um cliente para um protocolo parecido com IRC, mas com algumas coisas mais divertidas.

O JRuby é uma implementação da linguagem Ruby para rodar na JVM. Uma das vantagens de uma implementação de Ruby rodando em uma JVM é a possibilidade de tirar proveito de todas as outras coisas que também rodam na JVM.
Exemplos disto são o acesso a EJBs a partir de aplicações Ruby, utilização de código Legado Java, acesso a diversas bibliotecas que já existem para Java e ainda não existem para Ruby.
Outra grande vantagem é a possibilidade de escrever UIs utilizando SWING que é um dos frameworks para UI mais completos disponíveis hoje em dia, mas que quando utilizado com java, tem uma possibilidade muito grande de criar um código horrível.
E para solucionar este problema existe o Profiglacy, que é uma biblioteca Ruby para facilitar a utilização de SWING quando se esta trabalhando com o JRuby.

E neste pequeno tutorial vou criar uma aplicação simples utilizando esta biblioteca. A proposta é um Gerenciador de Tarefas bem simples, mas antes vamos ver do que estamos fugindo …

Criar UI em Java é muito flexível mas muito trabalhoso, o SWING é poderoso mas muito verboso, e a própria natureza do Ruby ja melhora um pouco isto, veja o código abaixo:

1
2
3
4
5
6
require 'java'
 
@frame = javax.swing.JFrame.new "Old Way, using only SWING from Ruby"
@frame.add(@lbl1 = javax.swing.JLabel.new("Master Title"))
@frame.pack
@frame.visible = true

Isto vai criar um jframe com um label, mas ainda assim iriamos precisar de todos aqueles gerenciadores de layout, além de ser necessário também atrelar a ordem de criação dos objetos a posição deles no layout, mas para tudo há uma solução.
O modo padrão de trabalho do Profiglacy melhora isto apenas um pouco, então vamos começar direto com a utilização da Layout Expression Language criada para utilização na biblioteca. É basicamente uma forma fácil de se utilizar um GridLayout …
O layout vai ser definido como uma String, o formato desta string é bastante simples:

  • [ .. ] – delimita o inicio e fim de uma linha
  • | – delimita uma celula da linha
  • label – qualquer nome utilizado dentro de uma celula se torna o nome da celula para referência posterior
  • _ – identifica uma celula em branco
  • (width) ou (width,height) – define a largura e/ou altura de um componente dentro da celula
  • * – Expande a celula
  • ^ ou . – Alinham o componente no topo ou na parte de baixo da celula respectivamente
  • < ou > – Alinham o componente a esquerda ou direita respectivamente

E é isto, simples assim …
Segue um exemplo para facilitar o entendimento:

1
2
3
4
5
[ <lbl_proj | cmb_project  ]
[ <lbl_activ | cmb_activ  ]
[ <lbl_date | inpt_date ]
[ <lbl_hour | inpt_hour ]
[ <lbl_description | (300,200)txt_description  ]

Este código define um Grid Layout de 5 linhas por duas colunas, todos os componentes da esquerda estão também alinhados a esquerda e o último componente da direita tem 300 pixels de largura por 200 de altura.

Agora algum de vocês se anima a escrever o código em java para montar isto? Não precisa nem usar o Grid Layout, garanto que vai ficar bem maior.

Claro que as vezes o LEL (Layout Expression Language) não é suficiente, mas para mim parece que isto torna 80% dos casos bastante simples, e quando for necessário isto sempre pode ser combinado com código padrão …

Deem uma olhada no código abaixo, é criada uma UI simples, combinando paineis.
O primeiro painel definido por “main_layout” organiza os grupos de componentes, o primeiro componente recebe um label e os outros dois recebem paineis, criados com LEL mas poderiam ser criados utilizando JPanel.new sem maiores problemas.
TaskManager.rb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
require 'java'
require 'rubygems'
require 'profligacy/swing'
require 'profligacy/lel'
 
module TaskManager
    class UI
      include_package 'javax.swing'
      include_package 'java.awt'
      include_package 'javax.swing.border'
      include Profligacy
 
      def initialize(title)
        main_layout = "[main_label][inputs][buttons]"
        layout = %Q{
        [ <lbl_proj | cmb_project  ]
        [ <lbl_activ | cmb_activ  ]
        [ <lbl_date | inpt_date ]
        [ <lbl_hour | inpt_hour ]
        [ <lbl_description | (300,200)txt_description  ]
        }
        @ui = Swing::LEL.new JFrame, main_layout do |c,i|
          c.main_label = JLabel.new "Information About  New Entry"
          c.inputs = Swing::LEL.new JPanel, layout do |d,i| 
            d.lbl_proj = JLabel.new "Project"
            d.cmb_project = JTextField.new
            d.lbl_activ = JLabel.new "Activity" 
            d.cmb_activ = JTextField.new 
            d.lbl_date = JLabel.new "Date"
            d.inpt_date = JTextField.new 
            d.lbl_hour = JLabel.new "Hour"
            d.inpt_hour = JTextField.new 
            d.lbl_description = JLabel.new "Description"
            d.txt_description = JTextArea.new
          end.build :auto_create_container_gaps => false
          c.buttons = Swing::LEL.new JPanel, "[button_save|button_cancel ]" do |e,i|
            e.button_save = JButton.new "Save"
            i.button_save = { :action => method(:save_clicked) }
            e.button_cancel = JButton.new "Cancel"
          end.build :auto_create_container_gaps => false
        end
        @ui.build(:args => "Simple LEL Example").default_close_operation = JFrame::EXIT_ON_CLOSE
      end
 
      def save_clicked(evt_type,event)
        puts "Test OK 2"
      end
 
      def self.start
        SwingUtilities.invoke_later proc { UI.new('My Test Frame with long title') }.to_runnable
      end
 
    end
end

Para executar o código precisamos apenas de um arquivo Ruby para chamar o método “start” definido na classe UI, claro que poderiamos ter utilizado o mesmo arquivo .rb, mas isto iria diminuir a possibilidadede reutilização daquele código, então criei o arquivo abaixo:
starter.rb

1
2
3
require 'TaskManager'
 
TaskManager::UI.start

Pronto, com este super mini tutorial, você ja pode escrever muito menos código para definir as suas interfaces Java de hoje em diante, para isto só precisa programar em Ruby :D

Cada vez mais me convenço que o melhor cenário é utilizar java como Plataforma em vez de como Linguagem :D

PS.: Eu sei que faltou explicar toda a parte de eventos, mas se não for possível inferir isto do exemplo apresentado, postem perguntas nos comentários que escrevo mais algo detalhado sobre isto (isto vai servir também pra ver se alguem lê o que eu escrevo aqui :D )

Tags: , , , , , , , ,

27 Nov 08 Certificação di Gratis: Prova beta para Sun Certified Developer for Java Web Services 5

Yeap, exatamente isto, a dica ta meio atrasada, mas só me registrei para fazer a prova hoje.
Para quem já tem a certificação SCJP (Sun Certified Java Programmer), pode fazer até o próximo dia 10/12/2008 “di gratis” a prova beta da nova certificação da SUN.
Não acredito que certificação prove alguma coisa, mas sempre ajuda colocar mais uma sigla no currículo, já que as empresas gostam delas por algum motivo :D

Quem quiser se inscrever, basta ligar para qualquer centro prometric ou acessar a página da prometric diretamente, não é necessário um voucher paraesta prova.

O conteúdo que estão pedindo não é nada demais para quem já trabalha com web services, segue o outline:

Exam Testing Objectives

  1. XML Web Service Standards
    1. Given XML documents, schemas, and fragments determine whether their syntax and form are correct (according to W3C schema) and whether they conform to the WS-I Basic Profile 1.1.
    2. Describe the use of XML schema in Java EE Web services
  2. SOAP 1.2 Web Service Standards
    1. List and describe the encoding types used in a SOAP message.
    2. Describe the SOAP Processing and Extensibility Model.
    3. Describe SOAP Message Construct and create a SOAP message that contains an attachment.
  3. Describing and Publishing (WSDL and UDDI)
    1. Explain the use of WSDL in Web services, including a description of WSDL’s basic elements, binding mechanisms and the basic WSDL operation types as limited by the WS-I Basic Profile 1.1.
    2. Describe how WSDL enables one to separate the description of the abstract functionality offered by a service from concrete details of a service description such as “how” and “where” that functionality is offered.
    3. Describe the Component Model of WSDL including Descriptions, Interfaces, Bindings, Services and Endpoints.
    4. Describe the basic functions provided by the UDDI Publish and Inquiry APIs to interact with a UDDI business registry.
  4. JAX-WS
    1. Explain JAX-WS technology for building web services and client that communicate using XML
    2. Given a set of requirements for a Web service, such as transactional needs, and security requirements, design and develop Web service applications that use JAX-WS technology
    3. Describe the Integrated Stack (I-Stack) which consists of JAX-WS, JAXB, StAX, SAAJ
    4. Describe and compare JAX-WS development approaches.
    5. Describe the features of JAX-WS including the usage of Java Annotations.
    6. Describe the architecture of JAX_WS including the Tools SPI that define the contract between JAX-WS tools and Java EE.
    7. Describe creating a Web Service using JAX-WS.
    8. Describe JAX-WS Client Communications Models.
    9. Given an set of requirements, design and develop a Web service client, such as a Java EE client and a stand-alone client, using JAX-WS.
    10. Given a set of requirements, create and configure a Web service client that accesses a stateful Web service.
  5. REST, JSON, SOAP and XML Processing APIs (JAXP, JAXB and SAAJ)
    1. Describe the characteristics of REST Web Services.
    2. Describe the characteristics of JSON Web Services.
    3. Compare SAOP web services to REST Web Services.
    4. Compare SAOP web services to JSON Web Services.
    5. Describe the functions and capabilities of the APIs included within JAXP.
    6. Describe the functions and capabilities of JAXB, including the JAXB process flow, such as XML-to-Java and Java-to-XML, and the binding and validation mechanisms provided by JAXB.
    7. Create and use a SOAP message with attachments using the SAAJ APIs.
  6. JAXR
    1. Describe the function of JAXR in Web service architectural model, the two basic levels of business registry functionality supported by JAXR, and the function of the basic JAXR business objects and how they map to the UDDI data structures.
    2. Create JAXR client to connect to a UDDI business registry, execute queries to locate services that meet specific requirements, and publish or update information about a business service.
  7. Java EE Web Services
    1. Identify the characteristics of and the services and APIs included in the Java EE platform.
    2. Explain the benefits of using the Java EE platform for creating and deploying Web service applications.
    3. Describe the functions and capabilities of the JAXP, DOM, SAX, StAX, JAXR, JAXB, JAX-WS and SAAJ in the Java EE platform.
    4. Describe the role of the WS-I Basic Profile when designing Java EE Web services.
  8. Security
    1. Explain basic security mechanisms including: transport level security, such as basic and mutual authentication and SSL, message level security, XML encryption, XML Digital Signature, and federated identity and trust.
    2. Identify the purpose and benefits of Web services security oriented initiatives and standards such as Username Token Profile, SAML, XACML, XKMS, WS-Security, and the Liberty Project.
    3. Given a scenario, implement Java EE based web service web-tier and/or EJB-tier basic security mechanisms, such as mutual authentication, SSL, and access control.
    4. Describe factors that impact the security requirements of a Web service, such as the relationship between the client and service provider, the type of data being exchanged, the message format, and the transport mechanism.
    5. Describe WS-Policy that defines a base set of constructs that can be used and extended by other Web specifications to describe a broad range of service requirements and capabilities.
  9. Developing Web Services
    1. Describe the steps required to configure, package, and deploy Java EE Web services and service clients, including a description of the packaging formats, such as .ear, .war, .jar, annotations and deployment descriptor settings.
    2. Given a set of requirements, develop code to process XML files using the SAX, StAX, DOM, XSLT, and JAXB APIs.
    3. Given an XML schema for a document style Web service create a WSDL file that describes the service and generate a service implementation.
    4. Given a set of requirements, create code to create an XML-based, document style, Web service using the JAX-WS APIs.
    5. Implement a SOAP logging mechanism for testing and debugging a Web service application using Java EE Web Service APIs.
    6. Given a set of requirements, create code to handle system and service exceptions and faults received by a Web services client.
  10. Web Services Interoperability Technologies
    1. Describe WSIT, the features of each WSIT technology and the standards that WSIT Implements for each technology and how it works.
    2. . Describe how to create a WSIT client from a Web Service Description Language (WSDL) file.
    3. Describe how to configure web service providers and clients to use message optimization.
    4. Create a Microsoft Windows Communication Foundation (WCF) client that accesses a Java web service.
    5. Describes the best practices for production and consumption of data interoperability between WCF web services and Java web service clients or between Java web services and WCF web service clients.
  11. General Design and Architecture
    1. Describe the characteristics of a Service Oriented Architecture (SOA) and how Web services fit to this model.
    2. Given a scenario, design a Java EE web service using Web Services Design Patterns (Asynchronous Interaction, JMS Bridge, Web Service Cache, Web Service Broker), and Best Practices.
    3. Describe how to handle the various types of return values, faults, errors, and exceptions that can occur during a Web service interaction.
    4. Describe the role that Web services play when integrating data, application functions, or business processes in a Java EE application.
    1. Endpoint Design and Architecture
    1. Given a scenario, design Web Service applications using information models that are either procedure-style or document-style.
    2. Describe the function of the service interaction and processing layers in a Web service.
    3. Design a Web service for an asynchronous, document-style process and describe how to refactor a Web Service from a synchronous to an asynchronous model.
    4. Describe how the characteristics, such as resource utilization, conversational capabilities, and operational modes, of the various types of Web service clients impact the design of a Web service or determine the type of client that might interact with a particular service.

Mais informações na página da certificação.
Depois da prova (vou fazer dia 10) eu posto o que achei das questões por aqui.

Tags: , ,

19 Nov 08 Curso básico de refactoring para quem é pobre e preguiçoso

Continuando com a seqüência de posts com títulos polêmicos que comecei dizendo que “Comentário no código é para os fracos“, segue um curso básico de refactoring para quem é pobre (por que vou utilizar o eclipse que é uma excelente IDE e alem de tudo é “di grátis”), e preguiçoso, por que o eclipse vai fazer quase todo o trabalho para nós.
O ponto de partida vai ser o “exercício” que deixei no final do post sobre comentários no código.
Par quem não quiser ler todo o outro post, o código inicial vai ser este abaixo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
package blog;
 
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
 
public class VeryBadlyNamedFile {
	private static final char[] asdfg = new char[] {'I', ' ', 'c', 'a', 'n', ' ', 'd', 'o', ' ', 'v', 'e', 'r', 'y', ' ', 'u', 'g', 'l', 'y', ' ', 'c', 'o', 'd', 'e'};
	private String an;
	private BufferedReader rfsdw;
	private FileReader temp;
 
	public VeryBadlyNamedFile(String an, BufferedReader rfsdw, FileReader temp) {
		super();
		this.an = an;
		this.rfsdw = rfsdw;
		this.temp = temp;
	}
 
	public void doIt() throws IOException {
		ctfiidne();
		startDoing();
		try {
			canIDoAnyThing();
		} catch (RuntimeException yicdet) {
			nowReallyDoIt();
		}
	}
 
	private void nowReallyDoIt() {
		firstDoTheOtherThing();
		reallyDoItInternal();
	}
 
	private void firstDoTheOtherThing() {
		rfsdw = new BufferedReader(temp);
	}
 
	private void reallyDoItInternal() {
		while (true) {
			try {
				imDoingIt();
			} catch (Exception e) {
				break;
			}
		}
	}
 
	private void imDoingIt() throws Exception {
		String s = rfsdw.readLine();
		if (s == null)
			throw new Exception("hahaha, I bet you did not understood the code");
		System.out.println(s);
	}
 
	private void ctfiidne() throws IOException {
		File a = new File(an);
		if (!a.exists()) {
			FileWriter wrfedsd = new FileWriter(a);
			wrfedsd.write(asdfg);
			wrfedsd.close();
		}
	}
 
	private void canIDoAnyThing() {
		if (new File(an).exists() && new File(an).canRead() && new File(an).canWrite())
			throw new RuntimeException();
	}
 
	private void startDoing() throws FileNotFoundException {
		File f = new File(an);
		temp = new FileReader(f);
	}
}

Antes de começar o refactoring, vamos definir o que é refactoring de uma forma bem simples:
Refactoring = Alterar partes do código de uma aplicação sem quebrar outras partes da aplicação que dependam daquele código.
Refactoring é uma forma de melhorar o design de um código existente enquanto ele continua funcionando.
Gosto muito de uma frase espetacular do Fowler, um dos papas do desenvolvimento ágil, que coloco abaixo:

“Any fool can write code that a computer can understand. Good programmers write code that humans can understand.”
-Martin Fowler et al, Refactoring: Improving the Design of Existing Code, 1999

Nos vamos utilizar os recursos de refactoring do Eclipse para transformar este lixo acima em alguma coisa legível, mantendo exatamente o mesmo comportamento, ou seja, sem quebrar o código que já funciona.
Para facilitar o trabalho, este tutorial (se é que pode ser chamado de tutorial), vai ser um simples “passo a passo” que eu utilizei para alterar este código no Eclipse, que é a minha segunda IDE preferida (a melhor de todas na minha opinião é o IntelliJ IDEA, mas se eu utilizasse este, não seria um tutorial para quem é pobre :D )
Siga os passos abaixo:

  1. Primeiro vamos renomear a classe, com o arquivo aberto, o cursos sobre o nome da classe (VeryBaclyNamedFile) pressione ALT+SHIFT+R e substitua o nome da classe por “TextFileToScreenPrinter” depois pressione “Enter”
  2. Agora esta na hora de alterar os nomes de alguns métodos. Repetindo exatamente o mesmo procedimento (ALT+SHIFT+R, altera nome, Enter), faça as seguintes alterações nos nomes de métodos e variáveis:
    • asdfg -> standardContentForNewFiles
    • an -> fileName (neste caso no parâmetro do construtor e na variável de instância)
    • ctfiidne -> ensureFileAlreadyExists
    • canIDoAnyThing -> abortIfCanNotReadOrWriteFile
    • startDoing -> createFileReader
    • temp -> rawFileReader (neste caso no parâmetro do construtor e na variável de instância)
    • rfsdw -> fileLineReader (neste caso no parâmetro do construtor e na variável de instância)
    • nowReallyDoIt -> printEachLineFromFileToConsole
    • yicdet -> e
    • firstDoTheOtherThing -> createLineReaderFromFileReader
    • reallyDoItInternal -> forEachLineInTheFilePrintItOnTheScreen
    • imDoingIt -> printNextLineOfFileToStdOutButFailIfThereAreNoMoreLines
  3. Agora com nomes menos ruins para os métodos vamos começar a organizar um pouco as coisas, dentro do método “abortIfCanNotReadOrWriteFile” selecione o trecho “new File(fileName).exists()”, pressione as teclas ALT+SHIFT+L e de o nome “fileExists” para a variável, agora repita a operação para o bloco “new File(fileName).canRead()” e de o nome “canReadTheFile” para a variável, e por último repita a operação com o bloco “new File(fileName).canWrite()” e nomeie a variável “canWriteToTheFile”.
  4. Agora podemos ler facilmente que a lógica deste método esta invertida, então precisamos negar as variáveis no “if” dentro do método “abortIfCanNotReadOrWriteFile”.
  5. Agora dentro do método “doIt”, podemos remover o try/catch.
  6. Editando o método “createLineReaderFromFileReader”, vamos mudar o tipo sendo utilizado para inicializar a variável “fileLineReader” para um java.util.Scanner, para isto basta substituir o bloco “new BufferedReader(rawFileReader);” por “new Scanner(rawFileReader);”. No momento em que isto for feito, o eclipse vai reclamar que não sabe o que é “Scanner”, então precione CTRL+1 com o cursor sobre a palavra “Scanner” e selecione “import java.util.Scanner”. Agora a reclamação é um “type mismatch”, simplesmente precione CTRL+F1 novamente e selecione a opção “Change the type of fileLineReader to Scanner”. E por último, vamos adicionar a seguinte linha neste método:
    1
    
    fileLineReader.useDelimiter("\n");
  7. Para melhorar um pouco o código, vamos remover os dois parâmetros extras do construtor da clase, o único parâmetro que deve ficar no construtor é o primeiro, que aponta para o arquivo que deve ser lido. Para fazer isto, coloque o cursor sobre o construtor e pressione ALT+SHIFT+C, remova os dois parâmetros extras no dialogo e clique em finish, como esta alteração vai causar um erro no código, será necessário clicar em continue no próximo dialogo. Para corrigir o erro, remova as linhas 19 e 21, o eclipse deve ter sublinhado estas linhas em amarelo.
  8. O código esta começando a parecer um pouco melhor, mas ainda precisa de alterações (no momento ele não deve estar nem compilando se você seguiu todos os passos até agora). Vamos então remover o método “printNextLineOfFileToStdOutButFailIfThereAreNoMoreLines”, e alterar o código do método “forEachLineInTheFilePrintItOnTheScreen” para algo parecido com o bloco abaixo:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    Iterable<String> lineIterator = new Iterable<String>(){
      @Override
      public Iterator<String> iterator() {
        return fileLineReader;
      }
    };
    for(String line : lineIterator){
      System.out.println(line);
    }
  9. Para melhorar o código do método, selecione a criação do iterator toda (deve ser da linha 40 a 45 no arquivo), pressione as teclas ALT+SHIFT+M e digite o nome “initializeLineIteratorFromLineReader” para o novo método.
  10. Agora utilizando o refactoring de rename (ALT+SHIFT+R) altere o nome da variável “lineIterator” para “linesInTheFile”, desta forma o último bloco do método pode ser lido exatamente igual ao nome do método.
  11. Agora no método “ensureFileAlreadyExists” vamos alterar o conteúdo para o seguinte bloco:
    1
    2
    3
    4
    5
    6
    7
    
    File file = new File(fileName);
    boolean fileExists = file.exists();
    if (!fileExists) {
      FileWriter fileWriter = new FileWriter(file);
      fileWriter.write(conteudoPadraoParaNovoArquivo);
      fileWriter.close();
    }
  12. Se você já esta se acostumando com os refactorings, vai perceber que o que foi feito foi um “extract variable” na condição do IF, e dois renames, um na variável que aponta para o arquivo e outro na variável que aponta para o FileWriter.
  13. Agora que quase todas as variáveis e métodos tem nomes decentes, podemos fazer algumas alterações na lógica, para limpar um pouco o código desta classe, como por exemplo, remover o método “createFileReader” e a variável “rawFileReader”, alterar o método “createLineReaderFromFileReader” para passar “new File(fileName)” como parâmetro na criação do Scanner.
  14. Isto vai gerar um erro de compilação, com o CTRL+1 poderemos adicionar a exception que falta no throws do método e tudo vai ficar OK.
  15. Podemos renomear o método “createLineReaderFromFileReader” para apenas “createLineReader”.

Pronto, o Eclipse acabou de nos ajudar a ter um código menos porco na classe do post sobre comentários de código.
Claro que o código ainda não esta nenhum primor, mas a idéia deste post era mostrar que é possível utilizar recursos da IDE para facilitar o refactoring de código porco quando este for encontrado.
E não se iluda, se você estuda para melhorar o seu conhecimento sobre desenvolvimento e ser um profissional cada vez melhor, provavelmente o código que você escreveu a dois meses atrás você ache muito ruim hoje.

Só para finalizar o post, o seu código deve ter ficado parecido com este:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
package blog;
 
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Iterator;
import java.util.Scanner;
 
public class TextFileToScreenPrinter {
	private static final char[] standardContentForNewFiles = new char[] {'I', ' ', 'c', 'a', 'n', ' ', 'd', 'o', ' ', 'v', 'e', 'r', 'y', ' ', 'u', 'g', 'l', 'y', ' ', 'c', 'o', 'd', 'e'};
	private String fileName;
	private Scanner fileLineReader;
 
	public TextFileToScreenPrinter(String fileName) {
		super();
		this.fileName = fileName;
	}
 
	public void doIt() throws IOException {
		ensureFileAlreadyExists();
		abortIfCanNotReadOrWriteFile();
		printEachLineFromFileToConsole();
	}
 
	private void printEachLineFromFileToConsole() throws FileNotFoundException {
		createLineReader();
		forEachLineInTheFilePrintItOnTheScreen();
	}
 
	private void createLineReader() throws FileNotFoundException {
		fileLineReader = new Scanner(new File(fileName));
		fileLineReader.useDelimiter("\n");
	}
 
	private void forEachLineInTheFilePrintItOnTheScreen() {
		Iterable<String> linesInTheFile = initializeLineIteratorFromLineReader();
		for(String line : linesInTheFile){
			System.out.println(line);
		}
	}
 
	private Iterable<String> initializeLineIteratorFromLineReader() {
	  Iterable<String> lineIterator = new Iterable<String>(){
			@Override
      public Iterator<String> iterator() {
	      return fileLineReader;
      }
		};
	  return lineIterator;
  }
 
	private void ensureFileAlreadyExists() throws IOException {
		File file = new File(fileName);
		boolean fileExists = file.exists();
		if (!fileExists) {
			FileWriter fileWriter = new FileWriter(file);
			fileWriter.write(standardContentForNewFiles);
			fileWriter.close();
		}
	}
 
	private void abortIfCanNotReadOrWriteFile() {
		boolean fileExists = new File(fileName).exists();
		boolean canReadTheFile = new File(fileName).canRead();
		boolean canWriteToTheFile = new File(fileName).canWrite();
		if (!fileExists && !canReadTheFile && !canWriteToTheFile)
			throw new RuntimeException();
	}
 
}

Atalhos do Eclipse Ganimede que todo preguiçoso inteligente deveria decorar

  • ALT+SHIFT+M -> Extract method
  • ALT+SHIFT+L -> Extract Local Variable
  • ALT+SHIFT+R -> Rename
  • CTRL+1 -> Quick Fix
  • ALT+SHIFT+X,J -> Executa aplicação Java
  • ALT+SHIFT+X,T -> Executa Unit Test
  • ALT+SHIFT+X -> Executar, se o tipo não for especificado, um menu será aberto em 5 segundos no canto inferior direito
  • CTRL+SPACE -> Code completion
  • CTRL+SHIFT+SPACE -> Parameter completion
  • CTRL+3 -> Atalho super mega mágico para qualquer tarefa dentro do eclipse,digite o nome do que quer fazer no dialogo que vai aparecer
  • ALT+SHIFT+S -> menu “source” onde ficam comandos como “Generate getters and setters” e “Override/Implement methods”
  • ALT+SHIFT+T -> Menu de refactoring

Atalhos do Eclipse apra usuáriso de MAC

  • COMMAND+OPTION+M -> Extract method
  • COMMAND+OPTION+L -> Extract Local Variable
  • COMMAND+OPTION+R -> Rename
  • COMMAND+1 -> Quick Fix
  • COMMAND+OPTION+X,J -> Executa aplicação Java
  • COMMAND+OPTION,T -> Executa Unit Test
  • COMMAND+OPTION+X -> Executar, se o tipo não for especificado, um menu será aberto em 5 segundos no canto inferior direito
  • CTRL+SPACE -> Code completion
  • COMMAND+3 -> Atalho super mega mágico para qualquer tarefa dentro do eclipse,digite o nome do que quer fazer no dialogo que vai aparecer
  • COMMAND+OPTION+S -> menu “source” onde ficam comandos como “Generate getters and setters” e “Override/Implement methods”
  • COMMAND+OPTION+T -> Menu de refactoring

E o atalho de teclado mais mágico de todos é:

COMMAND+SHIFT+L (CTRL+SHIFT+L em PCs) -> Lista os atalhos de teclado. :D

Acho que isto já esta bom para começar, se você for realmente um preguiçoso inteligente (o tipo que passa um pouco mais de tempo pensando para ter uma solução melhor agora e trabalhar menos no futuro), provavelmente você vai prestar atenção nos menus do eclipse e vai ir decorando as teclas de atalho com o tempo :D

PS.: Será que alguém vai ficar ofendido com o titulo deste post e vai ficar reclamando que não é pobre ou não é preguiçoso?

Tags: , , ,

24 Mar 08 Vou palestrar no FISL este ano :D

fisl-logo.jpeg

Acabei de ver que saiu na terceira lista de palestras aprovadas do FISL a minha palestra: Grails – Agilidade, produtividade e código bonito ao alcance de todos!

Então nos vemos no FISL, espero que os que aparecerem por la assistam a minha palestra, vai estar bem legal :D
Não vai ser só aquele CRUD básico que é apresentado em todos os lugares, estou preparando um esquema bem legal para vocês :D

<updated>
Acabou de ser publicado na grade de horários, a palestra vai ser dia 19 de abril as 16h :D
Espero que pelo menos um ou dois de vocês apareçam por la para que eu não fique sozinho na sala :D
</updated>

Tags: , , , ,

24 Mar 08 Pare de perder tempo escrevendo documentação do código que você escreveu (parte 1)

time_graphic.jpg

Não, eu não estou completamente louco, e não acho que documentação para o código escrito seja uma coisa completamente inútil.
Mas eu acredito que documentação desatualizada é pior do que nenhuma documentação …
E não estou incentivando a escrita de código completamente sem documentação …
E por último, só para constar, eu estou falando de documentação da regra de negócio implementada e não o manual do usuário …

Ok, mas como deixar de perder tempo escrevendo a tal da documentação?
A solução que me vem a cabeça é BDD, ou seja, Behavior Driven Development, junto com a tão falada, documentação executável …

Mas isto existe?
Sim existe, e o pessoal doRuby On Rails já esta bastante acostumado com isto, utilizando o RSpec.
Mas este post não é sobre Ruby On Rails e nem sobre RSpec, e sim sobre o Easyb, que é uma biblioteca para escrita de “Documentação Executável” utilizando Groovy, muito fácil de utilizar para testar código Java …

Para começar com a brincadeira, vou ir ao site do projeto e fazer o download do último release (atualmente 0.7)
criar um projeto java novo no eclipse.
criar uma pasta de nome lib e copiar os seguintes jars para a pasta:commons-cli-1.1.jar easyb-0.7.3.jar groovy-all-1.5.0.jar (todos vem no zip do easyb)
criar mais uma source folder de nome behavior
(O meu eclipse esta com o plugin para edição de código groovy instalado)

Crio um build.xml para executar os testes (ainda não existe um plugin para o eclipse, mas sinceramente, não achei necessário)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?xml version="1.0" encoding="UTF-8"?>
<project name="project" default="run_tests">
	<path id="all.path">
		<pathelement location="${basedir}/bin" />
		<pathelement location="${basedir}/bin-groovy" />
		<fileset dir="${basedir}/lib" includes="**/*.jar" />
	</path>
	<taskdef name="easyb" classname="org.disco.easyb.ant.BehaviorRunnerTask" classpathref="all.path" />
	<!-- ================================= 
          target: default              
         ================================= -->
	<target name="run_tests" description="--> description">
		<easyb failureProperty="easyb.failed">
			<classpath>
				<path refid="all.path" />
			</classpath>
			<behaviors dir="${basedir}/behavior">
				<include name="**/*Story.groovy" />
				<include name="**/*Specification.groovy" />
			</behaviors>
			<report location="story.txt" format="txtstory" />
			<report location="behavior.txt" format="txtbehavior" />
			<report location="easyb.xml" format="xmleasyb" />
		</easyb>
	</target>
</project>

Este build.xml declara a tag do easyb e executa todos os testes, alem de gerar os relatórios, que vocês vão gostar bastante …
Os tipos de relatórios variam bastante de acordo com a versão do easyb, a equipe de desenvolvimento esta melhorando bastante isto, eu estou utilizando aqui a versão do trunk do subversion, se quiserem baixar a mesma versão que uso aqui, podem baixar via git deste repositório : git clone git://github.com/urubatan/easyb.git
(Eu fiz um fork do projeto para adicioar algumas features, e ja estou enviando os patches para os desenvolvedores)

Agora vamos começar a brincadeira :D
Dentro do diretório behavior vou criar um diretório de nome users e um arquivo de nome PermitirRegistroDeUsuariosStory.groovy dentro deste último.
Ou seja, este arquivo vai conter os testes, e a documentação das regras de negócio sobre a criação de novos usuários no sistema …

Quero ter uma breve descrição da história nos meus relatórios, então adiciono uma tag description no inicio do arquivo (esta tag por enquanto só existe no meu fork).

1
2
3
description """Qualquer novo visitante do site deve poder se registrar no sistema, 
desde que as regras de validação definidas sejam atendidas.
Um usuário registrado podera alterar a sua senha sempre que desejar, mas a senha devera atender aos padrões minimos de segurança"""

As histórias são compostas basicamente de 4 comandos:
scenario – define um cenário da história, ou seja, um bloco contendo os outros 3 comandos
given – define a situação inicial
when – define um gatilho, uma ação do usuário que ira disparar alguma ação do sistema, este comando é opcional
then – define o que o sistema deve fazer, e o que vai ser testado

alem destes existe o “and” que atualmente é um comando que não executa nada, serve apenas para deixar o código mais legivel, mas isto vai mudar na próxima versão, o and vai repetir o comando anterior, semelhante ao que acontece no RSpec.

Conhecendo estes comandos podemos começar a escrever a nossa documentação :D
Vou adicionar alguns cenários a minha história e alguns detalhes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
scenario "Um novo usuário precisa confirmar a senha", {
	given "Um novo usuário", {
	}
	when "O usuário preenche o nome de usuário e a senha, mas sem confirmar a mesma", {
	}
	then "A validação do usuário deve falhar", {
	}
	when "O usuário preenche o nome de usuário e confirma a senha corretamente", {
	}
	then "A validação do usuário deve passar",{
	}
}
scenario "Um nome de usuário deve ser único no sistema", {
	given "Um usuário com o formulário preenchido corretamente", {
	}
	then "O registro deve criar o usuário no sistema", {
	}
	when "O nome de usuário ja existe no sistema", {
	}
	then "O registro do usuário deve falhar",{
	}
}
}

Com isto, podemos ver no diretório do projeto os seguintes arquivos criados:
behavior.txt que até o momento esta em branco

story.txt que contem o seguinte texto:

  Story: permitir registro de usuarios
    Qualquer novo visitante do site deve poder se registrar no sistema,
desde que as regras de validação definidas sejam atendidas.
Um usuário registrado podera alterar a sua senha sempre que desejar, mas a senha devera atender aos padrões minimos de segurança

    scenario Um novo usuário precisa confirmar a senha
      given Um novo usuário
      when O usuário preenche o nome de usuário e a senha, mas sem confirmar a mesma
      then A validação do usuário deve falhar
      when O usuário preenche o nome de usuário e confirma a senha corretamente
      then A validação do usuário deve passar

    scenario Um nome de usuário deve ser único no sistema
      given Um usuário com o formulário preenchido corretamente
      then O registro deve criar o usuário no sistema
      when O nome de usuário ja existe no sistema
      then O registro do usuário deve falhar

e easyb.xml que contem uma versão XML dos dois relatórios combinados …
Se você prestar atenção no story.txt, substituindo as palavras em ingles que fazem parte da DSL do easyb, por palavras em portugues, esta é uma ótima documentação para ser validada com o cliente, e com a garantia de que não vai ficar desatualizada por que este é o código fonte dos testes, por tanto sera alterado sempre que a regra de negócio for alterada …

Como assim?
Vamos seguir trabalhando no sistema, agora que ja temos o “behavior”, ou seja, o comportamento definido, vou adicionar algum código a esta história que devera ser testada sempre junto com o build automatizado do sistema:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package users;
 
description """Qualquer novo visitante do site deve poder se registrar no sistema, 
desde que as regras de validação definidas sejam atendidas.
Um usuário registrado podera alterar a sua senha sempre que desejar, mas a senha devera atender aos padrões minimos de segurança"""
 
scenario "Um novo usuário precisa confirmar a senha", {
	given "Um novo usuário", {
		user = new User()
	}
	when "O usuário preenche o nome de usuário e a senha, mas sem confirmar a mesma", {
		user.setName "validName"
		user.setPassword "aPassword"
	}
	then "A validação do usuário deve falhar", {
		ensureThrows(PasswordValidationException){
			user.validate()
		}
	}
	when "O usuário preenche o nome de usuário e confirma a senha corretamente", {
		user.setName "validName"
		user.setPassword "aPassword"
		user.setPasswordConfirmation "aPassword"
	}
	then "A validação do usuário deve passar",{
		user.validate()
	}
}
scenario "Um nome de usuário deve ser único no sistema", {
	given "Um usuário com o formulário preenchido corretamente", {
		user = new User('userName','password','password')
		userManager = UserManager.getInstance()
	}
	then "O registro deve criar o usuário no sistema", {
		userManager.create(user)
	}
	when "O nome de usuário ja existe no sistema", {
		user = new User('userName','otherPassword','otherPassword')
	}
	then "O registro do usuário deve falhar",{
		ensureThrows(UserAlreadyExistsException){
			userManager.create(user)
		}
	}
}

Pronto, este é todo o código desta história, e foi apenas o que eu escrevi até agora.
Agora preciso criar as classes User, UserManager e implementar os métodos corretamente, para que os testes passem., por que no momento os testes não estão nem rodando, ja que estas classes não existem ainda …

Criada a classe User:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package users;
 
public class User {
	private String name;
	private String password;
	private String passwordConfirmation;
 
	public User() {
		super();
	}
 
	public User(String name, String password, String passwordConfirmation) {
		super();
		this.name = name;
		this.password = password;
		this.passwordConfirmation = passwordConfirmation;
	}
 
	public String getName() {
		return name;
	}
 
	public void setName(String userName) {
		this.name = userName;
	}
 
	public String getPassword() {
		return password;
	}
 
	public void setPassword(String password) {
		this.password = password;
	}
 
	public String getPasswordConfirmation() {
		return passwordConfirmation;
	}
 
	public void setPasswordConfirmation(String passwordConfirmation) {
		this.passwordConfirmation = passwordConfirmation;
	}
 
	public void validate() {
		throw new RuntimeException();
	}
}

E a classe UserManager:

1
2
3
4
5
6
7
8
9
10
11
package users;
 
public class UserManager {
	private static UserManager instance = new UserManager();
	public static UserManager getInstance(){
		return instance;
	}
	public void create(User user){
		throw new RuntimeException();
	}
}

Os testes agora executam mas falham.

Implementando corretamente o método “validate” da classe User, ja temos 2 testes passando:

1
2
3
4
	public void validate() throws PasswordValidationException {
		if(password==null || passwordConfirmation==null || !password.equals(passwordConfirmation))
			throw new PasswordValidationException();
	}

E agora, finalizando a implementação do método create da classe UserManager.

1
2
3
4
5
6
7
8
	public void create(User user) throws InvalidUserException, PasswordValidationException, UserAlreadyExistsException{
		if(user==null)
			throw new InvalidUserException();
		user.validate();
		if(users.containsKey(user.getName()))
			throw new UserAlreadyExistsException();
		users.put(user.getName(), user);
	}

Todos os testes passam, e o nosso código funciona perfeitamente.

Claro que a DSL do easyb é bem mais completa que isto, é possível testar apenas a especificação de uma classe em vez de uma história completa (eu uso histórias para as regras de negócio importantes para o cliente, e especificações para classes internas do sistema), existem diversos “ensure” para validar o estado desejado, tudo isto vocês podem ver na página do projeto: http://www.easyb.org

E como eu falei antes, este é o código dos testes do sistema, desta forma, quando o usuário solicitar uma alteração, se altera o teste, depois se altera o código.
Quando o seu chefe pedir para você documentar o código escrito até agora, você executa os testes, e copia os txts gerados e envia para ele por e-mail.
Os testes você seria obrigado a escrever de qualquer forma, ja que acredito eu que se você leu até aqui, você acredita que testes de código são importantes.
Como você iria escrever os testes de qualquer forma, agora você precisa fazer uma coisa a menos, que é documentar aquilo que escreveu, por que algum dia você vai querer tirar férias, e outro desenvolvedor vai precisar alterar o código que você escreveu :D

Depois de ler até aqui, o que você acha do easyb?
O que você acha de Behavior Driven Development?
Você concorda comigo, quando digo que o easyb tornou possível BDD em Java? (Sim eu sei que existe o JBehave, mas eu acho o trabalhoso demais, e sei que é possível trabalhar com BDD utilizando qualquer xUnit, mas ai eu perco muito da vantagem da documentação executável)
Você vai pelo menos testar isto no seu próximo projeto?

Eu estou escrevendo alguns pequenos patches e enviando para eles sempre que sinto falta de alguma coisa, e fora isto o projeto vai ter diversas melhorias bastante significativas em pouco tempo!
Parabens aos desenvolvedores, e viva o Groovy, tornando o desenvolvimento Java mais divertido e menos trabalhoso!

Tags: , ,

21 Feb 08 Javascript não intrusivo com Lowpro e Prototype

Como eu disse que iria fazer, e fui cobrado no último rails podcads brasil, segue um post sobre o lowpro.
Isto não vai ser exatamente um tutorial, apenas uma coleção de dicas sobre esta excelente extensão para o prototype[bb], o Lowpro.
O Lowpro ja foi até transformado em um plugin para o rails, o UJS Rails Plugin, mas sinceramente, eu prefiro adicionar a meia duzia de linhas de javascript no meu application.js mesmo do que usar outro plugin só pra isto :D

Mas seguindo o baile, tudo o que vou escrever neste post, vocês podem usar com ou sem o rails, só sera necessário o prototype e o lowpro, inclusive o lowpro ja tem até uma versão que funciona junto com o jQuery[bb] para os que não gostam do prototype :D

Mas seguindo com o assunto deste post, o que vocês acham de adicionar alguns recursos Javascript e até mesmo AJAX[bb] em uma página pronta sem mexer no HTML gerado? nem para adicionar Javascript nos onclick, onblur, onXXX …
Na verdade, sera necessário adicionar pelo menos 3 linhas:

1
2
3
<script src="prototype.js" type="text/javascript" charset="utf-8"></script>
<script src="lowpro.js" type="text/javascript" charset="utf-8"></script>
<script src="meuarquivodescripts.js" type="text/javascript" charset="utf-8"></script>

A última linha, ou seja o “meuarquivodescripts.js” define o arquivo onde vamos trabalhar :D

Um dos recursos que eu acho mais espetaculares no lowpro, é o suporte a comportamentos …
Como assim?
imagine a seguinte situação:
Tenho uma página pronta, é uma página de listagem, e no final da tabela tem um link para a criação de um novo item, hoje toda a página é atualizada quando clico neste link, mas eu quero que apenas a parte da tablea seja substituida pelo formulário, em vez de recarregar a tela toda …
Bom isto é muito fácil de fazer :D
E não vamos precisar de praticamente nenhum código …
Claro, precisamos de alguma forma de identificar o link de adicionar novo objeto na tabela, então, consideremos que este e todos os links que quisermos que sejam abertos por ajax no lugar da tabela, tenham a classe “my_ajax_link”, e consideremos que a tabela esta dentro de uma DIV com ID ‘minha_tabela’…
Se isto for verdade, podemos fazer o seguinte:

1
Event.addBehavior({ 'a.my_ajax_link' : Remote.Link({update:'minha_tabela'}) });

Com isto, todos os links que tenham a classe “my_ajax_link” quando clicados vão ser executados via ajax, e vão substituir o conteúdo do elemento de id “minha_tabela” …

OK, mas é só isto que eu posso fazer com o tal de lowpro? E estes tais de comportamentos?

Na verdade o negócio é bem mais flexivel que isto :D
Vamos ver mais alguns exemplos …
Se você quiser executar algum código no momento em que a página aparecer para o usuário (não é no onload, o onload só é executado depois de toda a página carregada :D )
Basta fazer algo assim:

1
2
3
Event.onReady(function() {
  $$('h1').first().innerHTML += ' (Version ' + LowPro.Version + ')'; 
});

Isto vai mostrar a versão do Lowpro dentro da primeira tag H1 da página :D
O Event.onReady executa um código qualquer no momento em que o DOM da página estiver carregado, o que é bem antes de carregas as imagens, por exemplo, e o onload só sera executado depois de tudo carregado …

Outro exemplo bem simples:
Eu quero que quando o usuário colocar o mouse sobre um link ele fique verde, quando tirar o mouse ele volte a cor padrão, e quando clicar o link incremente um contador dizendo quantas vezes ele ja foi clicado …

Para isto precisamos criar um comportamento …

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var LinkBehavior = Behavior.create({
  initialize : function() {
    this.count = 0;
  },
  onmouseover : function() {
    this.element.addClassName('goo');
  },
  onmouseout : function() {
    this.element.removeClassName('goo');
  },
  onclick : function() {
    this.element.innerHTML = 'Clicks: ' + ++this.count;
    return false;
   }
});

O que vai fazer os nossos links mudarem de cor é a classe “goo”, por tanto para que as cores mudem como eu disse antes, é preciso criar a classe “goo” em algum arquivo css carregado pela página.

Mas só este código apenas cria uma classe “comportamento” que define que o objeto que tiver este comportamento vai receber a classe “goo” no evento onmouseover, tera esta classe removida no evento onmouseout e vai ter o conteúdo alterado quando clicado.

Para que isto funcione com todos os links da página, precisamos adicionar este comportamento aos links da página …

1
Event.addBehavior({ 'a' : LinkBehavior });

Pronto, agora todos os links vão ter o comportamento especificado pela classe.

Claro que alterar assim todos os links de uma página não é a coisa mais útil do mundo, mas se compararmos este último exemplo com o anterior, podemos ver que o lowpro, utiliza css selectors para identificar onde os behaviors devem ser aplicados …
Como assim?

  • a – todas as tags a
  • a.meulink – todas as tags a que tenham a classe “meulink”
  • a#link – a tag a com ID link
  • #qualquerid – qualquer tag mas que tenha o ID “qualquerid”
  • .qualquerclasse – qualquer tag que tenha a classe “qualquerclasse”

Tudo bem, esta melhorando, mas eu não curti esta idéia de ter que criar uma classe para definir o que eu quero que aconteça quando o usuário clicar em um link, não tem como fazer tudo isto com uma linha de código só?
Na verdade tem :D

1
Event.addBehavior({'a#bung:click' : function () {alert('Você Clicou no link');return false;}})

O que estamos fazendo agora é ligar uma função javascript ao evento onclick da tag a com ID bung.

E como é possível ver (talver não tão fácil por que a letra do código aqui no blog é meio pequena, o parâmetro apra a função addBehavior é um objeto, esta sendo utilizada a sintaxe de objetos JSON para passar os parâmetros, por tanto, isto quer dizer que podemos fazer algo parecido com isto:

1
2
3
4
5
Event.addBehavior({
  'a#bung:click' : function () {alert('Você Clicou no link');return false;},
  'a.ajax_link' : Remote.Link({update:'qualquerid'}),
  '.mudacoreconta': LinkBehavior 
})

Ou seja, passar diversos itens a cada chamada do Event.addBehavior.
Outra coisa interessante, é que novas chamadas, vão empilhar métodos na fila se chamada, ou seja, este código:

1
2
3
Event.addBehavior({'a#bung:click' : function () {alert('Você Clicou no link');return false;}})
Event.addBehavior({'a#bung:click' : function () {alert('Você Clicou no link novamente');return false;}})
Event.addBehavior({'a#bung:click' : function () {alert('Você Clicou no link');return false;}})

Vai mostrar 3 mensagens quando o link for clicado.

Uma outra coisa interessante do lowpro é que ele pode aplicar os comportamentos em objetos que forem carregados por uma chamada ajax também, para isto precisamos de mais uma linha de código (pode ser executada no inicio da aplicação)

1
Event.addBehavior.reassignAfterAjax = true;

Isto configura o lowpro para reaplicar os eventos após cada chamada AJAX.

Claro que podemos misturar isto com outras bibliotecas Javascript, por exemplo no meu pet project de planejamento doméstico, eu tenho o seguinte código no application.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var WindowedForm = Behavior.create({
   onclick : function() {
    if (remote_window){
      remote_window.destroy();
    }
    remote_window = new UI.Window({ theme: 'leopard', width: 600, height: 300, focus : true, minimize : false });
    remote_window.setAjaxContent(this.element.href, {method: 'get'});
    remote_window.center();
    remote_window.activate();
    remote_window.show(true);
    return false;
  } 
});
remote_window = false;
 
Event.addBehavior({ 'a.action_form' : WindowedForm });

Isto faz com que todos os links que tenham a classe action_form sejam abertos em uma janela modal criada pela biblioteca “prototype-ui”.

Ahh, e para finalizar com chave de ouro, uma dica para quem usa rails e will_paginate para a paginação, o código que vou mostrar agora utiliza a lowpro para fazer com que a paginação da will_paginate passe a funcionar via AJAX :D

1
2
3
Event.addBehavior({
  'div.pagination a' : Remote.Link({update:'nomedadiv'})
})

Pronto, só isto, agora é só fazer a action correspondente retornar apenas a tabela e não a página toda quando for uma requisição AJAX, e colocar uma div com ID “nomedadiv” na volta da tabela :D

E por último mas não menos importante, não esqueça de alterar o código no servidor para retornar ou Javascript para ser executado, ou a parte do HTML desejado, mas sem as tags html,head,body, …

O lowpro facilita muito o trabalho no client, mas as respostas as chamadas AJAX continuam necessitando ser implementadas adequadamente.

Bom, espero que este post ajude alguem :D
Quaisquer dúvidas podem perguntar por aqui mesmo :D

Tags: , , , ,

20 Feb 08 Tutorial de Grails do RSJUG – Neste sábado

Anuncio :D

Tutorial Desenvolvimento rápido de aplicações com Grails

Durante o tutorial será desenvolvida uma aplicação completa utilizando
o framework Grails[bb], contendo não apenas um CRUD como pode ser
encontrado na internet com facilidade, mas implementando lógica de
negócio no lugar correto, utilizando plugins do grails para facilitar
o trabalho, escrevendo testes para a aplicação, e o melhor de tudo,
qualquer participante com um notebook podera acompanhar o tutorial
passo a passo e aproveitar muito mais a oportunidade de descobrir como
desenvolver uma aplicação pode ser rápido e divertido.

Depois da aplicação básica desenvolvida, serão adicionados recursos
AJAX utilizando apenas Javascript não intrusivo, garantindo assim que
a aplicação tera recursos modernos para os browsers que suportarem
isto, e continuara funcionando para os usuários que não possuem
javascript habilitado, e tudo isto em apenas uma manha!

Data: 23/02/2008
Horário: 8:00
Custo: R$15 público em geral e R$10 associados SUCESU ou SEPRORGS
Local: Auditório do SEPRORGS.
Rua Felipe Camarão 690/404 – Bom Fim – Porto Alegre-RS

Inscrições : www.rsjug.org/eventos

Tags: , , , ,