quinta-feira, 30 de setembro de 2010

Duas instâncias do mesmo tomcat como serviços

Continuando minha saga anterior, agora eu precisava que a mesma versão do tomcat tivesse duas instâncias, uma para homologação e outra para produção.

Novamente, a versão instalada do tomcat tem que ser aquela com vários .jars, .bats no 'bin/', se não for o caso é só copiar os arquivos faltantes.

Primeiro pegue o arquivo tomcat6w.exe e faça uma cópia, por exemplo, tomcat6Homologacaow.exe (lembre-se de não ter nem '_' nem '-'). No prompt:
$service.bat install tomcat6Homologacao
Isso deve ter sucesso. Então, faça uma cópia de todo o diretório do tomcat para qualquer outro lugar. Desta cópia, apague a pasta bin, os conteúdos das pastas logs, temp, webapps, work. Edite seu server.xml para apontar para outras portas. Vá no tomcat6Homologacaow.exe, e nos parâmetros mude o CATALINA_BASE para a cópia recém-feita.

Pronto, vc deve ter dois serviços agora, um para cada tomcat! Ambos com o mesmo binário.

quarta-feira, 29 de setembro de 2010

Diferentes versões de tomcat como serviços

Miguxo @robertsonso me ajudou hoje a instalar um novo tomcat na mesma máquina.

Pegue a versão .zip do tomcat. Provavelmente vc quer a 32-bit Windows zip ou 64-bit Windows zip, que tem os wrappers e algumas DLLs nativas, uns .bat's.

Abra este zip no buraco que você quiser. Vá até o diretório bin e edite o tomcat6w.exe para algo como qualquerCoisaQueVcQueiraw.exe. Pelo prompt, vá até o diretório bin e execute:
            $ service install qualquerCoisaQueVcQueira
Importante notar que 'qualquerCoisaQueVcQueira' não pode ter - ou _, senão acontece um erro como 'Alpha sei lá das quantas'.

No diretório conf, edite as três portas para alguma não utilizada. PRONTO!
Ainda vou descobrir como fazer para rodar várias instâncias do mesmo tomcat.

Group by

Tem uma coisa diferente nessa vida é o group by do sql.

Era uma vez duas entidades:

@Entity
public class Entidade1{
      @OneToMany
       private List<entidade2> lista;
}

@Entity
public class Entidade2{
       private String desc;
    
       @ManyToOne
       private Entidade1 entidade1;
       //outras coisas
}


Não carece de muita imaginação para perceber como ficavam essas duas tabelas, usando JoinColumn para o OneToMany. A pesquisa era: uma lista de 'Entidade1' a partir de um trecho de 'desc'.

A primeira tentativa era com groupBy. O grande problema ali é entender que o group by não retorna nada que não tenha sido agrupado, só podemos retornar o que está no group by ou funções agregadoras.

Então, o sql:
select e2.desc from Entidade2 e2 where e2.desc like '%algumaCoisa%' group by e2.id_entidade1
simplesmente não faz sentido e não funciona. 'Desc' é diferente para cada registro, como o BD vai adivinhar o que ele tem que retornar? Ele não vai concatenar tudo e jogar numa coluna só, não. Ele não vai pegar o primeiro, tem que ter garantias que é igual para todos os caras do grupo.

Por outro lado, uma opção seria (não, eu não gosto de usar join):
select * from Entidade1 e1, Entidade2 e2
where e2.entidade1_id = e1.id
and e1.id in
(
     select e3.entidade1_id from Entidade2 e3
     where e3.desc like '%algumaCoisa%'
) order by e1.id, e2.desc
O ponto é que isto retorna um registro para cada Entidade2 que existem na Entidade1 relacionadas, então na interface isso teria que ser tratado de alguma forma. Chato, mas às vezes necessário.
Importante notar que o SQL acima tem 'in' - o que tem sido bem lento na prática para mim - então seria bom tentar transformá-lo em um 'exists'.

Agora, já que estamos no hibernate e somos gente grande, não custa um HQL de gente:
select distinct e2.entidade1 where e2.desc like  '%algumaCoisa%'.

Se fosse Criteria, teria que fazer aquele DISTINCT ROOT para voltar só uma Entidade1 por grupo de Entidade2's.
 

sábado, 25 de setembro de 2010

Update com subquery

Quando um sistema já está em produção, temos que tomar alguns cuidados no transporte dos dados antigos para que continuem funcionando.

No exemplo, criamos o campo 'placaMae' em pedido, e buscamos a partir de codigoBios.getPlacaMae()

update Pedido set placa_mae_id =
(select pm.id from Codigo_Bios c, Placa_mae pm, Pedido p
where c.id = p.codigo_bios_id
and c.placa_mae_id = pm.id
and p.id_pedido = Pedido.id_pedido)

terça-feira, 14 de setembro de 2010

quinta-feira, 9 de setembro de 2010

JSF e os campos disabled

Meu projeto é JSF (sun) + RichFaces + Jquery para a camada de View. E olha só o que o destino me reservou.

Eu tinha os seguintes campos:
<h:inputText value="#{mBeanMeuBean.atributo1}" style="botoesChatos" id="meuCampo1" disabled="#{mBeanMeuBean.edicao}"/>
<a4j:commandLink id="btnEditarCampo1" rendered="#{mBeanMeuBean.edicao}" oncomplete="liberarEdicao('meuCampo1', this);" value="Habilita Campo 1"/>


<h:inputText value="#{mBeanMeuBean.atributo2}" style="botoesChatos" id="meuCampo2" disabled="#{mBeanMeuBean.edicao}"/>
<a4j:commandLink id="btnEditarCampo2" rendered="#{mBeanMeuBean.edicao}" oncomplete="liberarEdicao('meuCampo2', this);" value="Habilita Campo 2"/>


Isto é, são dois campos inicialmente desabilitados, em que é necessário clicar num link antes de abrí-los para edição. À prova de usuário distraído.
O javascript 'liberarEdicao' se limita a retirar o atributo 'disabled' do campo via jQuery e sumir com o link.

Simplesmente, mesmo clicando no link próprio, mexendo no campo, mandando para o mBean via a4j:commandButton, a modificação NÃO chegava lá por nada. Como se tivesse um 'immediate=true', o que não tinha. É verdade que esse bean tinha keepAlive, mas o que raios ocorria?

Pensei que fosse alguma coisa no meu salvar, que não estivesse habilitando os campos antes de enviar (já tive este problema no Struts). Lá vou eu colocar no onclick do meu salvar:

onclick="jQuery('.botoesChatos').removeAttr('disabled');"

Mas, pasmém, isso NÃO resolveu. Tirei isso do botão, mas retirei o 'disabled' do h:commandButton e passei para o jquery no onload da página.


jQuery(function() {

if(edicao){
jQuery('.botoesChatos').attr('disabled', 'disabled');
}
});

Agora o problema mudou. Os campos que eu realmente editava/habilitava, chegavam no bean. Se eu editasse apenas um, o outro não era enviado. Aí achei que era o problema de habilitar antes de mandar salvar e, de fato, ao recolocar o onclick que citei acima, resolveu.


D'onde tiro que: ao colocar um campo como 'disabled' direto na tag h:inputText, o JSF *NÃO* vai trazer esse cara de volta nem que vc mude-o por javascript. Colocando este 'desabilitar' via jQuery, vc tem que obrigatoriamente habilitá-lo antes de enviar, senão este campo também não será enviado.

Alguma outra sugestão?