quarta-feira, 19 de outubro de 2011

Notes/XPages - Deletar um documento e todas seus filhos recursivamente

Bem, sabemos que um documento, em Lotus Notes, pode ter documentos filhos (Responses). E esses documentos filhos podem ter outros documentos filhos e assim vai.
Criei um Javascript Server-Side de XPages para deletar um documento e todos os seus filhos recursivamente.
Ele é bem útil para colocar em uma View, com uma coluna para deletar certo documento.

Segue o script:


function removerDocumentoComResponses(id, retornar){
 var doc:NotesDocument = database.getDocumentByUNID(id);
 var documentos:NotesDocumentCollection = doc.getResponses();
 var documentosDeleteUNID:java.util.List = new java.util.ArrayList();
 var documentoDelete:NotesDocument = documentos.getFirstDocument();
 while(documentoDelete != null){  
  if(documentoDelete.getResponses().getCount() != 0){
   documentosDeleteUNID.addAll(removerDocumentoComResponses(documentoDelete.getUniversalID(), true));
  }
  else{
   documentosDeleteUNID.add(documentoDelete.getUniversalID());
  }
  documentoDelete = documentos.getNextDocument(documentoDelete);
 }
 documentosDeleteUNID.add(doc.getUniversalID());
 documentos = null;
 if(retornar){
  return documentosDeleteUNID;
 }
 var iterator:java.util.Iterator = documentosDeleteUNID.iterator();
 while(iterator.hasNext()){
  var unid = iterator.next();
  database.getDocumentByUNID(unid).removePermanently(true);
 }
}

Esse código deve ser chamado passando o UniversalID do documento e um false no primeiro argumento.

sábado, 17 de setembro de 2011

Java - Criando Thumbnail de uma imagem

Postarei hoje uma forma que encontrei, e que estou usando, para gerar thumbnail de uma imagem armazenada em byte[].

No meu caso, estou armazenando a imagem no banco de dados e tenho um bean Imagem que tem o atributo 'arquivo' do tipo byte[]. No momento que quero exibí-lo como um thumbnail, eu uso tal código. Esse código pode ser usado em Servlets, por exemplo. Estou usando para gerar um StreamedContent para o p:graphicImage do PrimeFaces.


Vamos ao código:


@Transient
private static final int MAX_THUMBNAIL_WIDTH = 100;
 
@Transient
public byte[] getThumbnail(byte[] arquivo){
   ImageIcon imageIcon = new ImageIcon(arquivo);
   Image inImage = imageIcon.getImage();
   double scale = (double) MAX_THUMBNAIL_WIDTH / (double) inImage.getWidth(null);
 
   int scaledW = (int) (scale * inImage.getWidth(null));
   int scaledH = (int) (scale * inImage.getHeight(null));
 
   BufferedImage outImage = new BufferedImage(scaledW, scaledH, BufferedImage.TYPE_INT_RGB);
 
   AffineTransform tx = new AffineTransform();
   if(scale < 1.0d){
      tx.scale(scale, scale);
   }
 
   Graphics2D g2d = outImage.createGraphics();
   g2d.drawImage(inImage, tx, null);
   g2d.dispose();
 
   ByteArrayOutputStream baos = new ByteArrayOutputStream();
   try {
      ImageIO.write(outImage, "jpeg", baos);
      return baos.toByteArray();
   } catch (IOException e) {
      e.printStackTrace();
   }
   finally{
      try {
         baos.close();
      } catch (IOException e) {
         e.printStackTrace();
      }
   }
   return null;
}

quarta-feira, 7 de setembro de 2011

Java EE - Por onde começar?

Bom, quando eu queria começar a estudar para Java EE, tracei uma lista de passos de estudo que tem dado certo. Então pensei em ajudar aqueles que estão no Java SE, ou que nem mesmo começou a estudar Java e quer desenvolver para a web usando Java.

Começando com quem nem mesmo conhece Java SE:
- Aprenda pelo menos os conceitos e desenvolva programas em Java SE. Eu indico o livro "Use a cabeça! Java" ou sua versão em inglês (Head First! Java), caso a pessoa não tenha problemas com o mesmo. Eu estudei pelo Deitel e me arrependo. É um livro com leitura muito intediante e cansativa. Não cheguei a ler o que recomendei, mas já me foi muito recomendado e já li "Head First! HTML, CSS & XHTML", da mesma série, e adorei a forma como o livro é feita. Então, não tente pular as coisas, tenha boa lógica de programação e saiba os conceitos de Java.

Para quem já sabe programar em Java SE:
- Se você não sabe HTML, é melhor nem começar a estudar Java EE enquanto não aprender. Também é recomendável aprender Javascript e, se quiser fazer sites com boa aparência sem um webdesigner, saber CSS também. Eu aprendi HTML (e também XHTML, que exiguem mais algumas regras) e CSS com o livro que eu citei antes: Head First! HTML, CSS & XHTML. A versão dele em português é a mesma coisa, trocando "Head First" por "Use a cabeça". Já postei aqui um site com vários e-books em inglês, sendo que lá eu encontrei esse e outros livros. Javascript eu aprendi vendo video-aulas, lendo artigos e treinando mesmo. Lendo o livro que eu disse, você já vai praticar fazer webdesign básico.
- Aprenda a usar JDBC, caso não o saiba ainda. JDBC é usado para se comunicar com o banco de dados. E uma aplicação WEB sem banco de dados não é nada.
- Após aprender os itens acima, inicie seus estudos em JSP e Servlets. Comece aprendendo os conceitos do protocolo HTTP. Depois, aprenda os conceitos de servlet e como uma JSP é feita. Quando chegar em JSP, você verá bastante HTML misturado em scriptlets e depois aprenderá que é sempre bom evitá-los. Estude JSTL e, preferencialmente, desenvolva um projeto simples para fixar as idéias. Boa parte dos meus estudos, eu fiz vendo video-aulas. Mas a maioria, eu aprendi no desenvolvimento de um projeto. A medida que eu ia precisando das coisas, ia estudando, aprendendo e implementando. Aprendi, inclusive, JasperReports/iReport, que é um framework para gerar relatórios.
- Quando estiver seguro com JSP, Servlet e JDBC, comece a estudar os frameworks de mercado. Eu sugiro que inicie com Hibernate. Está cansado de fazer tanto SQL com JDBC? Pois o Hibernate (que segue a especificação JPA), após ser corretamente configurado, vai fazer todo o mapeamento objeto-relacional para você e facilitará todas as operações com banco de dados. Dificilmente você precisará criar queries, e se precisar, poderá usar HQL que funciona em qualquer banco de dados. Outro benefício é que ele funciona independente do banco de dados. Se você fosse mudar o BD de um projeto em JDBC, teria que mudar bastante as SQL. Com o Hibernate, você apenas muda alguns parametros na sua XML de configuração. Depois, vá em busca de outros frameworks (eu fui atrás de JSF e depois pretendo aprender Spring, mas você pode escolher Struts ao invés de JSF, por exemplo). Sugiro que pesquise qual framework tem mais futuro, é mais usado no mercado e o que cada um tem a te oferecer, antes de começar a estudar.

sexta-feira, 1 de julho de 2011

Notes/XPages - Listar campos do Custom Control ou XPages atual

<Bom, a um tempo atrás tive que pegar todos os campos de dada página através de um Server-Side Javascript. Normalmente, podemos usar um getComponent("nomeDoComponent"), mas quando queremos pegar de forma geral todos os campos da página, não há um método getAllComponents.
Então criei um código recursivo que retorna uma List de components. Sendo que essa lista já contem os components, não é necessário usar getComponent.
Bem, vamos ao código:

function pegarCamposPagina(viewRoot:javax.faces.component.UIViewRoot){
    var listaCampos:java.util.ArrayList = new java.util.ArrayList();

    function iterate(component:javax.faces.component.UIComponent){
        //testa de qual tipo é o component
        if(component instanceof com.ibm.xsp.component.xp.XspInputText ||
 component instanceof com.ibm.xsp.component.xp.XspInputRichText ||
 component instanceof com.ibm.xsp.component.xp.XspInputTextarea ||
 component instanceof com.ibm.xsp.component.xp.XspInputCheckbox ||
 component instanceof com.ibm.xsp.component.xp.XspInputRadio ||
 component instanceof com.ibm.xsp.component.xp.XspSelectManyCheckbox ||
 component instanceof com.ibm.xsp.component.xp.XspSelectOneRadio ||
 component instanceof com.ibm.xsp.component.xp.XspSelectOneMenu){
            listaCampos.add(component);
        }

        //testa se o component atual tem filhos
        if(component.getChildCount() > 0){
            var lista:java.util.List = component.getChildren();
            for(var i:int=0; i<lista.size(); i++){
                iterate(lista.get(i));
            }
        }
        return null;
    }
    iterate(viewRoot);

    return listaCampos;
}

Para usar esse script, pode-se criar uma Server-Side JavaScript Library e importar na página, ou simplesmente jogar no evento. Deve-se chamar esse metodo da seguinte forma:
pegarCamposPagina(getView())

O método getView() retorna a viewRoot da página. Então enviamos para o método e ele faz chamadas recursivas até listar todos os componentes. Caso queira-se apenas os campos de uma certa table ou panel, por exemplo, é necessário passar o getComponent("nomeDoComponente") para o método. Ele também funcionará.

sexta-feira, 27 de maio de 2011

XPages - Livro sobre XPages

Segue o link para download de um livro sobre XPages escrito pela própria IBM:


http://www.wowebook.com/web-development/mastering-xpages.html

- 784 páginas
- Editora: IBM Press
- Data de publicação: Janeiro de 2011

Boa leitura.

quinta-feira, 26 de maio de 2011

Site para E-Books em inglês

Gostaria de indicar aqui um ótimo site para e-books (sobre TI) em inglês.
Nele, podemos achar inúmeros livros sobre diversas linguagens e, além disso, caso esteja interessado em um livro em especial que eles não tenham, podemos postar no fórum deles pedindo pelo livro. Já fiz isso e em poucos dias eles disponibilizaram.
O site é o seguinte: http://www.wowebook.com/. Aproveitem.

terça-feira, 15 de março de 2011

XPages - Como validar campos

Bom, falaremos sobre como validar campos em XPages.

Há campos, como o TextField que, em suas propriedades, há uma aba Validation, onde podemos definir duas validações básicas: campo requerido e tamanho do valor inserido no campo.

Mas outros campos, como ComboBox, esta aba não está disponível.

Além de que essas validações são básicas demais e muitas vezes precisamos de validações mais avançadas. Então devemos ir na aba All Properties e procurar por "validators".
Nessa propriedade, podemos clicar no + e adicionar diversos tipos de validators.
Aqui serão apresentados os principais validator para um campo, sendo eles: xp:validateConstraint, xp:validateLength, xp:validateRequired (quando você marca campo requerido naquela aba validator, esse validator é criado aqui automaticamente) e o mais importante de todos, que pode substituir todos os outros, xp:validateExpression.

Primeiro falaramos de duas propriedades comum a todos esses validators: loaded e message. A propriedade loaded é simplesmente quando esse validator será considerado. Você pode inserir uma expressão em JavaScript ou simplesmente colocar true ou false. A propriedade message é muito importante, pois ela é a propriedade que define qual a mensagem que aparecerá no "Display Error" ou "Display Errors" para o usuário ver.

Agora vamos falar individualmente dos validators.

xp:validateConstraint

Aqui você usará Expressões Regulares (regex). Caso você saiba fazê-las, você pode simplesmente inserir na propriedade regex. Caso não, pode procurar na internet regex feitas para validar o que você quiser. Por exemplo: uma regex que valide se o email é valido. Um site que eu aconselho para procurar regex prontas é http://regexlib.com/
Nele há várias regex para validar várias coisas, porém é em inglês e tem poucas regex brasileiras (como por exemplo para validar CEP, visto que nosso CEP é diferente do Zip Code deles). Você pode usar esse site http://www.pagecolumn.com/tool/regtest.htm para testar as regex que você encontrar lá, testando o que é validado e o que não é.
O problema desse validator é que ele é um pouco limitado. Se a validação é muito avançada, você dificilmente conseguirá bons resultados com esse.

xp:validateLength

Tem a mesma função daquele validator da aba Validation. Simplesmente você coloca o tamanho mínimo e/ou máximo que a STRING inserida deve ter. Lembre-se, ele não validará o tamanho de um número.

xp:validateRequired

Simplesmente torna o campo requerido. Mesma função do encontrado na aba Validation.

xp:validateExpression

Com esse você pode fazer qualquer tipo de validação usando JavaScript. A propriedade clientScript é apenas usada quando você quer fazer alguma validação com Client-Side JavaScript. Mas no geral, usaremos expression para usar o Server-Side JavaScript.
Você deve clicar no diamante e clicar em compute value, então abrirá a seguinte janela:
Nessa janela você poderá usar códigos JavaScript para validar seu campo. Para pegar o valor do campo que você está validando, você deve usar:
getComponent("nomeDoCampo").getSubmittedValue()
Então você processa em cima dele. É usado o SubmittedValue porque no momento em que aquele campo está sendo validado, o valor dele está sendo submetido ao servidor. Mas no caso de você pegar o valor de um outro campo que não seja onde está sendo feito o validator, você deve usar apenas Value, da seguinte forma:
getComponent("nomeDoOutroCampo").getValue()
Lembrando que quando seu código retornar true, significa que foi validada a entrada, que não houve problemas. Quando seu código retornar false, houve algum erro e a mensagem de erro definida será emitida.
Veja exemplos:
Uma outra forma é você, na aba da esquerda dessa janela, selecionar Control Declaration Snippets. Lá estarão todos os campos de sua página. Dando um clique duplo em um dos campos, será inserido automaticamente uma variavel recebendo o getComponent do campo. Nas linhas abaixo, você pode usar essa variável e verá que os métodos em cima dessa variável serão completados.



Esses são os principais validators (pelo menos para mim). Em geral, você pode usar apenas o validateExpression para tudo.
Uma coisa importante de se fazer quando você criar um validator é colocar true na propriedade disableClientSideValidation.
Isso fará com que suas mensagens apareçam no Display Error ou no Display Errors, de acordo com qual você estiver usando.
Para quem não conhece esses dois componentes, eles são components para mostrar mensagens de erro para o cliente. Você pode inserir um Display Error do lado ou perto do campo que você quiser e nas propriedades dele selecionar para qual campo ele será relacionado. O Display Errors simplesmente mostrará uma lista de erros de todos os validators da página.

XPages - Trabalhando com DbColumn e DbLookup

Assim como no Notes, podemos usar @DbColumn e @DbLookup em XPages através de JavaScript. Há apenas algumas diferenças.


A sintaxe básica desses dois comandos em XPages é:

@DbLookup(dbName:string, viewName:string, key:string, colNumber:int) : any
@DbLookup(dbName:string, viewName:string, key:string, fieldName:string) : any
@DbLookup(dbName:string, viewName:string, key:string, colNumber:int, keywords:string) : any
@DbLookup(dbName:string, viewName:string, key:string, fieldName:string, keywords:string) : any
DbColumn(dbName:string, viewName:string, colNumber:int) : any

Bastante parecida com a sintaxe usada no próprio Notes.
Mas devemos ter muita atenção ao trabalhar com esses dois comandos, pois eles podem retornar: Array, String ou null. Diferente de comandos convencionais que usamos em JavaScript, esse comando pode retornar instancias diferentes de acordo com seu resultado. Caso encontre mais de um resultado, ele retorna uma instancia de Array com os resultados; caso encontre apenas um resultado, ele não retornará um Array com um elemento, mas sim o elemento; caso não encontre nada, ele retornará null. Então sempre devemos tratar os resultados de acordo com o que pode aparecer. Mas de tudo isso que falei acima, o @DbColumn tem apenas uma diferença, onde retornaria null, retorna "".

Eu sugiro usar o seguinte código ao usar esses 2 comandos:

var x = @DbLookup(@DbName(), "ViewQualquer", key, 1);
if(x instanceof Array){
    //Código para quando retornar um Array
}
else{
   if(x == null){
        //Código para quando não retornar resultados
    }
    else{
        //Código para quando retornar apenas um elemento
    }
}



var x = @DbColumn(@DbName(), "ViewQualquer", 1);
if(x instanceof Array){
    //Código para quando retornar um Array
}
else{
   if(x == ""){
        //Código para quando não retornar resultados
    }
    else{
        //Código para quando retornar apenas um elemento
    }
}

terça-feira, 1 de março de 2011

XPages - Como validar se o documento foi modificado por outro usuário

Os métodos que encontramos para validar isso costumam ser os mais complicados possíveis, geralmente dando 'lock' no documento, rodando agents, etc. Procurando como fazer isso, acabei tendo a idéia de desenvolver um simples validator que o fizesse.
Essa validação é algo muito importante, para um usuário não sobescrever o que o outro acabou de fazer e também para evitar conflitos em geral.
Bom, vamos lá.

Após já ter um NotesXspDocument definido em Data da XPage ou Custom Control, vá em eventos da página, entre no nome definido em Data por você (por padrão, document1) e então no evento "postOpenDocument". Apenas insira um evento com o seguinte código:


viewScope.acessado = @Now();


Agora crie um validator (validateExpression) em apenas UM dos campos da página. Em expression insira o seguinte código:

if(!document1.isNewNote()){
    var modificado:Date = document1.getDocument().getLastModified().toJavaDate();
    var acessado:Date = viewScope.acessado;
    return modificado.getTime() < acessado.getTime();
}
else{
    return true;
}

Agora vá em message do validator e selecione Compute value. Apenas insira o seguinte código (modificando a mensagem, caso queira):

var modificado:Date = document1.getDocument().getLastModified().toJavaDate();
return "O documentou foi modificado por outro usuário em " + modificado.toString() + ", atualize a página para evitar conflitos!";


Pronto! Agora, caso um usuário abra a página e enquanto ele edita um outro salvou, o validator irá validar isso e avisá-lo. Lembrando, é claro, que deve-se ter um Error Message vinculado ao campo ou um Error Messages na página.

segunda-feira, 28 de fevereiro de 2011

Notes/XPages - Debugando um Java Agent

Existe uma forma de debugar o Java Agent no Designer, mas é totalmente instável, o Designer trava e tem que ser fechado o tempo todo.
Então vamos usar o Eclipse para debugar nosso Agent Java. É recomendável que se deixe um eclipse apenas para isso, pois vamos mudar a JRE do Eclipse para usar a JRE do Notes. Caso use o mesmo Eclipse para outras aplicações Java, terá que ficar alterando o JRE padrão o tempo todo.

Primeiramente, crie um projeto java no eclipse como o nome que preferir. Crie a classe JavaAgent. Cole o seguinte código:
import lotus.domino.*;

public class JavaAgent extends AgentBase {

    private Database database;
    private Session session;

    public JavaAgent() {

    }

    public JavaAgent(Session s, Database d) {
        this.session = s;
        this.database = d;
    }

    //
    public static void main(String[] args) {
        Session sess=null; 
        Database db=null;
        JavaAgent ag;

        // Initialize Notes
        NotesThread.sinitThread(); 

        try {
            sess = NotesFactory.createSession();  // start a Notes session
            db = sess.getDatabase("", 

            "nomeDaDatabase.nsf");  // simulate home database for agent
            ag = new JavaAgent(sess, db);  /* simulate agent object  with session and database*/
            ag.NotesMain();   // call main routine of agent
        }
        catch(NotesException ne) {
            System.out.println(ne.id + " " + ne.text);
        }
        catch (Exception e)    {
            e.printStackTrace();
        }
        finally {
            try { 
                if (db != null) db.recycle(); 
                if (sess != null) sess.recycle(); 
            }
            catch (Exception x) {}
            NotesThread.stermThread();
        }
    }

    public void NotesMain() {
        Session session = null;
        AgentContext agentContext = null;
        try {
            if (this.session != null) // Already have an agent context.  
                {
                session = this.session;
                }
            else {  // Need to get agent context.  
                session = this.getSession();
                if (session==null) throw new 

                NotesException(NotesError.NOTES_ERR_ERROR,  "Could not get current session at start of agent.");
                agentContext = session.getAgentContext();
                if (agentContext==null) throw new 

                NotesException(NotesError.NOTES_ERR_ERROR,  "Could not get agent context at start of agent.");
                        this.database = agentContext.getCurrentDatabase();
                if (this.database==null) throw new 

                NotesException(NotesError.NOTES_ERR_ERROR,  "Could not get current database at start of agent.");
            }
        }
        catch(NotesException ne) {
            System.out.println(ne.id + " " + ne.text);
            return;
        }
        catch (Exception e)    {
            e.printStackTrace();
            return;
        }

        //Your code goes here!!!
    }
} 
 Aparecerá erros em todos os objetos do Notes, pois ainda não colocamos a JVM/JRE do Notes.

Vamos mudar o JRE do Eclipse. Vá no menu: Window > Preferences.



Vá em Java > Installed JREs.


Clique em Add, selecione Standard VM, clique em Next. Em JRE home, clique em Directory e selecione o diretório da JVM do Notes. Exemplo: C:\Program Files\IBM\Lotus\Notes\jvm

Coloque um nome de sua preferência e clique em Finish. Agora marque a JVM do Notes como padrão.

Apenas dê OK.
Agora vamos para a segunda parte. Quando você estiver programando o Java Agent no Eclipse, ele já vai usar a JVM do Notes, estando disponíveis todos comandos vindos do Notes para Java Agent. Mas também precisamos usar essa JVM na hora de executar o programa e debugar.
Vá em Run > Run Configurations.

Dê um clique duplo em Java Application para criar uma nova configuração. Coloque o nome que quiser (usei JavaAgent), selecione seu projeto e a Main Class.

Vá na aba Arguments e, caso o Working Directory não esteja já definido para o diretório de seu Notes, clique em Other e o selecione.



Certifique-se de que em JRE esteja selecionado em Runtime JRE: Project JRE (<nome que você colocou na jvm>).

Clique em Apply e Close. Agora você pode programa e debugar seu Java Agent no Eclipse.
Agora apenas modifique a linha:
db = sess.getDatabase("", "nomeDaDatabase.nsf");
colocando o nome/caminho de sua database.
Programe seu Java Agent apartir da linha:
//Your code goes here!!!

-------------------------------------------------------------
Fonte: http://www.bobzblog.com/tuxedoguy.nsf/dx/the-2-headed-beast-debugging-domino-java-agents-with-eclipse
Adaptação: Fernando Camargo