Dynamic Linkage em Servlet

Olá pessoal,
gostaria de saber quais são os contras de se usar o pattern Dynamic Linkage em um Servlet.

Abraços,

Nunca ouvi falar desse pattern…alguma literatura boa sobre ele?

Segundo o livro “PATTERNS IN JAVA VOLUME 1” (Mark Grand):
“dynamic linkage allows a program, upon request, to load and use arbitrary classes that implement a known interface”. Na verdade, eu criei um Servlet mais ou menos assim (snippet):

[code]public void init(ServletConfig config) throws ServletException {
//carrega as ações que podem ser executadas pelo servlet
.
.
}

public void doPost(HttpServletRequest request, HttpServletResponse response) throws java.io.IOException, javax.servlet.ServletException {
/verifica se determinada ação pedida por um "request" pode ser executada por este servlet; se sim, carrega dados sobre esta ação./
MyAction act;
try{
act = (MyAction)Class.forName(action.getClassname()).newInstance();//dynamic linkage…
try{
//obtém paramêtros para executar a ação, verifica algumas outras coisas…
Object obj = act.execute(param);// executa a ação…
//faz algumas outras coisas…
}catch(Exception e){
//
}
}catch(Exception e){
//
}
//continua fazendo outras coisas…
}[/code]

Pois bem. E agora a pergunta: quais os problemas de se fazer isso (ou quais os problemas nesta implementação)?

Alguns problemas em potencial que eu vejo:

  • Se vc estah definindo suas actions em um arquivo de configuracao (o que eh uma otima ideia), podem ocorrer conflitos (duas acoes com o mesmo nome), o que da uma dorzinha de cabeca;

  • ClassLoaders não sao sempre gentis e voce nunca pode confiar neles quando o assunto é webapp. Cada container tem um comportamento ligeiramente diferente nesse assunto, entao todo cuidado na implementacao é pouco;

  • Esse pattern implora pra ter outro pattern agregado, o Command (olha o método execute() aí, geeente :)), entao eh uma boa dar uma estudada nas melhores implementacoes possiveis dele tb (lembrando que o Prevayler tambem usa Command pattern, e ate agora nao tem nenhum framework web pra ele - DICA DICA DICA :D)

Bom, por enquanto é só :slight_smile:

[]'s
-cv

Sim, as ações estão mapeadas em um arquivo de configuração “à la” XML. Mas, convenhamos, este problema de confiltos é basicamente de quem vai criar as ações :wink: .

Isso é algo realmente preocupante e estou tentando criar um Classloader próprio (ajuda? :wink: ). E também estou aberto a outras sugestões.
Mas, como já disseram em algum lugar aqui no fórum, “se o meu bom programa (o que não é bem o caso) prejudica o bom funcionamento do seu programa, se vira” :lol: .

Na verdade, o DL não implica no uso de Commands. Fui eu que acabei fazendo o mix entre os dois patterns para que eu tenha a flexibilidade desejada (aliás, implementei o Pattern Command usando tanto Interface quanto Abstract Class). Mas, pessoalmente, acho que o Command complementa o DL e vice-versa.
Agora, sobre a DICA DICA DICA, eu não entendi: para quem não tem framework Web? Para o Prevayler??

Abraços,

[quote=“Daniel Quirino Oliveira”]Estou tentando criar um Classloader próprio (ajuda? :wink: ). E também estou aberto a outras sugestões.
Mas, como já disseram em algum lugar aqui no fórum, “se o meu bom programa (o que não é bem o caso) prejudica o bom funcionamento do seu programa, se vira” :lol: . [/quote]

Pois é, os desenvolvedores de containers pensaram mais ou menos nisso quando fizeram os mecanismos de classloading - o WebLogic sendo famoso por arrancar lágrimas de desespero do pessoal que resolve tocar nessa área, digamos, perigosa da J2SE :slight_smile:

Uma sugestão talvez seja usar o mais básico possível (Class.forName) antes de tudo, e caso a classe não seja encontrada, tentar usar outro mecanismo (um ClassLoader proprio, talvez). No WebWork, se nao me engano, é possível fazer isso.

[quote=“Daniel Quirino Oliveira”]
Na verdade, o DL não implica no uso de Commands. Fui eu que acabei fazendo o mix entre os dois patterns para que eu tenha a flexibilidade desejada (aliás, implementei o Pattern Command usando tanto Interface quanto Abstract Class). Mas, pessoalmente, acho que o Command complementa o DL e vice-versa.
Agora, sobre a DICA DICA DICA, eu não entendi: para quem não tem framework Web? Para o Prevayler??[/quote]

Isso :slight_smile:

Eu acabei escrevendo uma classe PrevaylerAware pra criar sistemas prevalentes no WebWork, mas nao ficou tão legal quanto eu queria, dada alguma impedância entre o WebWork e o Prevayler… :frowning:

eu estava lendo agora

esse DL parece mais um idiomismo que um design pattern, de tao especifico que eh. a gente usa isso a todo segundo…

se voe tivesse delegado essa decisao para uma classe, seria um factory.

Pois é… e tem alguma linha que divida idiomas de patterns? :slight_smile:

Hahahaha… boa…

Vc podia mesmo misturar tudo isso que eles falaram: uma factory de commands. O problema com o servlet é o ciclo de vida, vc ia acabar se beneficiando muito pouco disso.

Sobre o seu próprio class loader, o ideal seria que ele fosse subclasse da implementação que carregou o servlet. Como isso é inviável, eu sugiro que vc não crie class loader nenhum, mas utilize “o classloader da sua webapp”, assim:

  // este método está no servlet!
  public Class getActionClass(String name) {
    ClassLoader loader = this.getClass().getClassLoader();
    if (loader == null) {
      // use boot classloader - nunca deveria entrar aqui, mas vai saber
      return Class.forName(name);
    }
    else {
       return loader.loadClass(name);
    }
  }

  }

Se vc faz assim, quando sua webapp morrer (por exemplo, a cada deploy), sua classe dinâmica não fica lá.

Se vc achar realmente necessário criar seu próprio class loader, leia o tutorial do GUJ e passe this.getClass().getClassLoader() como pai pra ele.

boa sorte!!

Carregar classes dinamicamente é uma grande dor de cabeça caso elas não vão estar no classpath. Sem falar que a API de reflection é bem chatinha de usar. Se tiver como usar apenas Class.forName() eu recomendo.

Outra coisa é pra vc desconciderar o codigo que o dukejeffrie postou, ele provavelmente nao sabe do seguinte fato:

Class.forName(xyz);
é a mesma coisa que
Class.forName(xyz, this.getClass().getClassLoader());

Ou seja, a função dele é redundante, pq não faz nada alem do que 1 simples Class.forName() já faz.

Uma coisa que eu realmente recomendaria é separar o codigo de classloading a parte, pq voce pode ter um Linkage error se alguma classe faltar ou tiver assinatura errada, e principalmente, pode rolar 1 ExceptionInInitializerError se o construtor estatico der throw. Sem falar que teu codigo não iria conseguir dar catch nessas exceptions, já que são descendentes de Error.

So não resolva implementar class reloading, pq isso da trabalho!

Não é uma preocupação necessária, uma vez que as classes que o servlet vai carregar dinamicamente estarão no mesmo webapp. E caso o usuário configure o carregamento de uma classe que não pertença ao seu webapp, isso vai resultar numa exception, já que isso pode se caracterizar uma tentativa de hacking.

Hmmm… algo a se pensar.

catch(ExeptionInInitializerError error) { ... }
catch(LinkageError error) { ... }

:wink:

sobre separar o código de classloading é uma boa idéia, mais por uma questão de qualidade de código, do que por uma questão de tentar “resolver” os possíveis problemas de linkage errors (que não necessariamente podem ser resolvidos).
outra idéia que andei tendo é a de usar um banco de dados de XML (à la Apache Xindice) para armazenar os XMLs que configuram o aplicativo. Qual a opinião de vocês?

Com certeza seria bom separar, mas nao da para entender. Porque ele nao pode dar catch nessas exceptions? Ele pode mais que perfeitamente dar o catch. O que tem o “ja que sao descendentes de Error” com isso? Voce nao sabia que podia dar catch em Errors, como o cv mostrou, nao eh isso?

Paulo,
Sabia sim, porem eu me referia ao exemplo que o daniel deu apenas, qualquer Throable pode ser catch’ed e como toda excessao em java obrigatoriamente tem que ser subclasse de Throable todas podem ser interceptadas.
So tava advertindo ele disso pq exceptions do tipo Error são como RuntimeException, não são checadas.

Quando a usar 1 banco xml, pode ser e, se quiser, guarde as classes ali usando base64. hehehehehe

Mas acho que voce mudou de ideia rapidamente, porque voce escreveu o seguinte, anteriormente:

mas voce conseuge sim dar catch, como voce se corrigiu depois, ou aprendeu depois.

bem, acho que voce percebeu que estou querendo ser chato com voce, da mesma maneira que voce faz apontado erros dos outros (E o dos outros nao foram erros basicos como esse).

Nao existe necessidade nenhuma de ficar apontado erros e ficar falando que as pessoas “nao sabem” aqui no forum, ninguem esta medindo forcas com ninguem. Voce eh um cara que conehce bastante, e seria legal voce ajudar e dar toques, e perceber que voce tambem erra e ninguem fica te apontando (a nao ser eu agora, que fui estupido).

Nossa, é verdade!! É a mesma coisa!!

Mas não é pra desconsiderar meu código. Pq se vc tá fazendo linkagem dinâmica, vc pode precisar de um class loader separado (um URLClassLoader, por exemplo), e daí vc tem que passar esse class loader para achar suas classes dinâmicas.

O que tá no classpath, mesmo que seja no classpath da webapp, não precisa de nada disso, né? É só declarar e pronto.

Class reloading, como vc disse para não fazer, é indispensável. Ou vc ganha de graça (pq o tomcat te deu) ou vc não tem opção a não ser fazer isso. Por que se vc usa forName e depois vc dá um redeploy, vc pode ter leak de memória. Ou pior, a classe já carregada fica lá eternamente e vc não consegue instanciar seu código novo sem reiniciar o container.

Sua única opção, neste caso, é ter class reloading. Isso é fácil, desde que vc use sempre o mesmo classloader do servlet para linkar suas classes dinâmicas. Na hora de simplificar, passei o this.getClass().getClassLoader(), mas esse nem sempre vai ser o class loader correto. Se vc usar outro class loader, o class loader do servlet tem que ser pai deste, seão vc pode ter problemas para encontrar algumas classes.

Daniel, se suas classes estão no class path do webapp (ou seja, no WEB-INF/classes ou num jar do WEB-INF/lib), essa historia de Dynamic Linkage é desnecessária.

[]s

Eu tava vendo, implementar class reloading não é tao dificil quanto parece, é basicamente 1 HashTable e codigo pra modificar o nome da classe antes de dar load nela e pra isso existe bcel.