| Autor |
Mensagem |
|
|
O principal problema do JSF é que ele gerencia a criação da HTML final e também o formato das URLs. Em aplicações RIA para web 2.0, aonde você tem que mexer diretamente na estrutura DOM da página gerada e se preocupar com o formato e estrutura das suas URLs, você acaba se ferrando por causa do JSF.
Para demonstrar isso dê uma olhada na HTML gerada pelo JSF e você vai ver muita coisa gerada automaticamente. Então tente implementar no seu template JSF, sem usar nenhuma gambiarra escrota, algum efeito na página via javascript (com ou sem jQuery). Provavelmente você vai quebrar a cara. Se conseguir, tente então baixar algum conteúdo por ajax e alterar a estrutura da página dinamicamente com base na resposta do ajax. Vai quebrar a cara de novo. Tente personalizar algum detalhe do CSS, quebrou a cara de novo!
É aí que está o problema do JSF: Uma vez que ele toma para si a tarefa de gerenciar a criação da HTML, você acaba perdendo a liberdade de personalizá-la, sendo obrigado a seguir as regras impostas pelo JSF, e para alguns tipos de aplicações, estas regras impostas não são aceitáveis.
Uma possível saída para esse problema é você criar os seus componentes JSF personalizados para fazer isso, mas aí você acaba perdendo a produtividade prometida pelo JSF e tem ainda a tarefa extra de ajustar os seus componentes as necessidades do JSF, uma tarefa árdua. Assim acaba sendo mais simples, mais fácil e mais rápido fazer tudo com javascript e HTML você mesmo, pois o JSF vai acabar se tornando um elefante branco inútil no sistema.
Para sistemas que são compostos basicamente de telas de cadastro, consultas e relatórios CRUD, você pode usar o JSF e seja feliz. No entanto, você também pode usar uma grande gama de outras ferramentas (ex: REST + JSP + jQuery) e também ser do mesmo jeito.
No entanto se você quer fazer um site cheio de animações e efeitos, carregamento dinâmico de dados em tempo real, etc, o JSF não é uma boa ideia.
Talvez você decida que o que você precisa é simples o suficiente para que o JSF dê conta e você vai produzir muito bem e mais rápido do que se estivesse usando alguma outra coisa. Até que em uma bela sexta-feira 13 de lua cheia, o cliente chega com um requisito de fazer a sua tela de consulta de situação de venda de produtos que é completamente estática, ter que monitorar em tempo real a atividade do fluxo de provisionamento de venda de produtos, para que o operador não precise ficar dando F5 a toda hora e possa agir imediatamente sem estourar o prazo máximo de 30 minutos para a conclusão da venda. Isso daí você pode fazer com Ajax e jQuery, mas... OH NO!
|
 |
|
|
|
Dá para ir para isso sim, mas um programa focado nisso dificilmente você vai achar. Normalmente você vai pegar algo mais abrangente ou relacionado também com alguma outra área relacionada e focar nisso para fazer a sua a dissertação, artigos, etc.
|
 |
|
|
Difícil eu dar uma opinião do Maker atualmente. Não tenho visto mais ele por aí.
O que penso é que a softwell se adaptou a realidade e preparou o departamento de marketing para lidar com o problema da grande publicidade negativa. No início a propaganda era algo como "chegou a ferramenta revolucionária que vai mudar a humanidade". Com o início da publicidade negativa, eles começaram a reagir com coisas do tipo "programadores têm medo da ferramenta porque não querem perder o emprego" e "tem um monte de gente que não conhece e fica criticando, mas quem conhece de verdade gosta", e por aí vai.
Com o tempo, cerca de um ano depois, deu para ver que eles estavam com uma tática diferente. Ao invés de falar das mil maravilhas da ferramenta milagrosa aos sete ventos, atirando para todos os lados, eles mudaram de tática e se tornaram mais discretos. Passaram a escolher a dedo os possíveis clientes e então investir em um marketing extremamente focado, de forma a minimizar o barulho gerado.
Que o maker consegue dar conta de casos mais simples, isso era óbvio até mesmo para os mais ferrenhos críticos desde o começo. Uma ou outra tarefa mais complexa ele dá conta. Mas foram enumeradas uma série de razões aonde ele não dá conta e dificilmente daria sem uma reformulação total praticamente do zero, ou então que a solução do maker sai muito mais complexa do que seria em qualquer outra linguagem. Não acho que isso tenha mudado muito. Nestes três anos suponho que a API tenha aumentado, alguns bugs tenham sido corrigidos, alguns recursos novos adicionados, mas nada que vá mudar o conceito do que ele é ou pretende ser, mas ressalto que isso é suposição.
O principal problema do maker era o marketing agressivo, irresponsável e anti-ético e questões comerciais igualmente duvidosas que giravam em cima dele. Tivesse ele um marketing mais sincero e uma estratégia comercial mais amigável, provavelmente teria sido muito melhor sucedido, embora haja algumas teorias conspiratórias que dizem que este não era o objetivo deles. Tenho poucas informações de como estão hoje em dia, mas acredito que eles aprenderam do pior jeito possível a não fazer um marketing desse tipo tão descaradamente e inconsequentemente, que pelo menos sejam mais discretos e racionais.
|
 |
|
|
Jesuino Master wrote:
fredferrao wrote:
Jesuino Master wrote:Não é bug, é técnica de SEO.
Tem muitos sites assim.
Com essa técnica aproximamos a WEB Humana da WEB das máquinas e tals
Colocar todo o título do tópico na URL é a técnica, agora permitir que qualquer coisa possa ser colocada la e mesmo assim abrir o mesmo link? Esta é a questão.
É uma boa questão. Temos defensores dos dois lados e tals.
Considerando que o post é um recurso, deveríamos ter uma URI que referencia-se ele unicamente. Para isso, o ID já serve. Para efeitos de SEO, colocam o texto do tópico também, pois aumenta a relevância em SEngines. A grande questão é se fixar isso, o título do post pode mudar, mas o post continuar existindo, Ou seja, iremos trocar o identificar único do recurso, mas o recurso ainda é o mesmo.
Em outras palavras, se trocarmos o título iremos quebrar um monte de links! Da forma que está não impactará em links existentes se mudarmos o título...
Na verdade, vamos supor que Fulano cria o tópico com id 123 e com título AAA. A URL do tópico vai ter o id 123 e AAA como parte dela. Se algum espertinho trocar AAA por BBB, tem que dar 404.
Depois fulano altera o título do tópico para CCC e obtém-se uma nova URL com o id 123 e CCC nela. Quem trocar CCC por BBB tem que ter um 404 como resposta.
No entanto ainda há a URL antiga. Quem acessar com id 123 e AAA, tem que obter um status 301 e redirecionar para a URL nova. Enfim, neste caso o GUJ deveria salvar todas para um determinado id de tópico, não só o título que é parte da URL, mas também os títulos antigos que redirecionem para o novo.
|
 |
|
|
http://www.htmlstaff.org/ver.php?id=23581 wrote:
Exemplo de ou exclusivo em C (XOR):
Fonte desta pérola: http://www.htmlstaff.org/ver.php?id=23581
Alguém avisa ele sobre o operador ^, acho que ele não conhece...
|
 |
|
|
Dei uma olhada no seu plano.
1. Pra que duas impressoras? Uma já é mais que suficiente.
2. Quantos funcionários você teria? Deu a entender que seria um junior, um pleno e um sênior. Para o pleno e sênior em São Paulo-SP o salário está bem baixo.
3. Vender ERP por unidade? Apenas chover no molhado.
4. Desenvolver um ERP em um mês? Só em sonho.
Não acho a sua ideia viaável.
|
 |
|
|
dipold wrote:Olá,
Segue atualizações:
Devido ao fato de que o JPA 2.0 não ser suportado pelo Google App Engine, eu resolvi fazer duas implementações de DAO, sendo uma para JPA 1.0 e a outra para JPA 2.0.
Assim para projetos que não utilizem o GAE utiliza-se a implementação mais recente do JPA.
Dessa forma eu acho que legitimei a existência de um DAOFactory certo?
Se a resposta é positiva então há necessidade de criar uma configuração para isso no lugar da constante DEFAULT_FACTORY_NAME.
Quanto ao tratamento de exceções eu andei relendo sobre o assunto pois difere bastante do que estou acostumado em Delphi. Por enquanto apenas removi os tratamentos nos pontos que você indicou.
Com relação ao AbstractEntity, pergunto: O que você faria em um projeto com 200 entidades se, por exemplo, por força de uma nova legislação fiscal, você tivesse que criar um atributo novo que todas entidades devem possuir?
Explico: Um exemplo recente aconteceu em uma empresa que trabalhei pois o fisco para homologar sistema de PAF, queria que o sistema gerasse um relatório de todos os registros que houveram alterações diretas no banco de dados. E os homologadores pedem para abrir o BD e gerar uma modificação em um registro aleatório de qualquer tabela e esperam que ela saia no relatorio do sistema. Para tanto foi criado um campo hash em todas as tabelas para controlar as alterações que não são executadas pelo próprio sistema.
Neste caso/exemplo, com AbstractEntity meu problema não seria mais simples de resolver, bastando criar esse campo hash apenas no AbstractEntity, que reflete automaticamente para todas entidades?
Um outro caso, e se eu quisesse implementar uma estratégia diferente de geração de código para um banco de dados que possui uma arquitetura diferente da relacional (Ex. noSQL do GAE) não seria mais fácil através dessa implementação centralizada?
Quanto ao JUnit e Log4J vou dar uma estudada e tentar implementar no feriadão.
Abs.
Herança no JPA tem várias limitações. Do jeito que está você ainda não vai ter problemas, a menos que você comece a trazer listas de AbstractEntity, a tentar fazer relacionamentos polimórficos, ou trabalhar com métodos que têm parâmetros do tipo AbstractEntity. Se você tomar cuidado em fazer isso e não forçar nenhuma entidade a herdar de AbstractEntity, você está bem.
Quanto a este problema que você falou, me soa ser um caso excepcional e incomum. E quando você tem que aplicar a mudança em todas as tabelas exceto em uma? E quando você tem uma tabela que por ter alguma característica completamente diferente ela tem uma estrutura completamente diferente das outras? Nestes casos você pode ter problema com "herança maldita", quando uma classe herda coisas que você não queria que fossem herdadas, mas você é obrigado por algum motivo a usar herança. E este problema em especial que você falou pode ser solucionado de outra forma: com classes @Embedded.
Quanto ao DAOFactoryImpl, já que deseja mantê-lo, sugiro alterar o métodp getInstance():E daí você pode eliminar o loadInstance().
Eu ainda não vejo como você poderia ter mais do que uma DAOFactory.
|
 |
|
|
Para que serve o parâmetro s se você usa getSession() dentro do método ou seta a sessão com o seu sapiturSF.getInstance()? Em lugar nenhum você usa o parâmetro s.
Porque você usa em um ponto getSession().getTransaction() e em outro usa getTx()? Isso não pode te dar um resultado inconsistente?
E eu otimizaria este código evitando repetições (e talvez você acabe matando alguns bugs ao fazer isso).
Por exemplo, isto daqui:Pode ser simplificado nisso:E isto daqui:Pode ser simplificado nisso:
|
 |
|
|
Porque que Destino na tabela Conhecimento é String e CodDes em Destino é Long? Vou assumir que deveria ser Long. Para que serve o campo Destino na tabela Conhecimento se aparentemente você não o utiliza?
Eu mapearia assim:Sua JPQL ficaria bem simples:Daí você pega o resultado e manda para a JSP. Ficaria algo assim:
|
 |
|
|
Bem, vamos lá.
Já ficou bem melhor. Nada mais a dizer quanto aos pontos 1 e 7.
Quanto ao ponto 2, primeiramente na sua DAOFactory você tem o método getDao(Class<?> daoClass). Observe que agora o parâmetro não é mais utilizado (pois agora o IDAO não é mais genérico), portanto agora você pode eliminar este parâmetro (e isso vai simplificar os seus BOs). Com isso, todas as instâncias dos seus DAOImpl serão iguais, então se você quiser poderá colocá-la em cache, transformar em singleton, ou utilizar o construtor diretamente pois ele se torna um objeto extremamente leve.
Eu nem ia falar do CriteriaBuilder por enquanto. Que bom que você já foi direto nisso.
Quanto as exceções (ponto número 5), vamos ao começo. Primeiramente na classe DAOImpl. Note que lá você captura RuntimeException apenas para relançar como Exception. E se ao invés de fazer isso, você simplesmente não a capturasse e deixasse propagar?
O grande segredo do tratamento de exceções, é saber quem pode tratar a exceção de forma eficiente (usando o catch), e quem não pode (deve relançar ela, ou lançar uma outra exceção tendo a primeira como causa).
Pense bem, uma PersistenceException vinda do JPA não tem como ser tratada no próprio método. Portanto deixe ela se propagar. Só isso já diminui o seu throws Exception para throws PersistenceException. No entanto, se você for subindo as camadas, vai ver que ninguém vai saber tratar essa exceção de forma adequada, o único tratamento possível seria no controller, aonde ele dá um catch (Exception e) ou um catch (Throwable t), gera um log e manda um erro para o usuário. O motivo de não ter aonde tratar o PersistenceException é porque ele de fato não é algo tratável, não há muito o que fazer exceto cuspir um erro na cara do usuário e talvez gerar alguns logs no caminho. Como não é razoável que alguém tente tratar a PersistenceException e ela é uma RuntimeException exatamente por causa disso, então você pode simplesmente apagar a cláusula throws e deixar ela se propagar sem fazer nenhum tratamento especial local, deixando para que o tratador de erro genérico do controller se vire com ela.
Quanto ao ponto 4, nos seus BOs, aplicadas as mudanças que sugeri sobre o ponto 2, você vai ter isso:
Qual é o motivo de você não fazer simplesmente isso?Ou então isso?A menos que você tenha um motivo forte o suficiente, você vai ver que não precisa do DAOFactory.
No entanto, caso queira manter o DAOFactory do jeito que está, sabemos que o DEFAULT_FACTORY_NAME é "JPA". Asssim, isso:
É otimizado pela JVM nisso:
Que por sua vez é novamente otimizado para isso:
Vamos supor que ao invés do nome da classe, o createNewInstance recebesse uma referência da própria classe (o que já eliminaria o método getClass(String)). Como a classe DAOImpl está dentro do seu JAR, então é seguro referenciá-la diretamente. Você teria isso:
Que efetivamente é a mesma coisa que isso:
E assim o seu método se tornaria isso:
Não há como uma exceção ser lançada ali, então podemos eliminar o try e o catch. Logo, temos isso:
E então, em todos os lugares aonde você tem isso:
Você poderia substituir por isso:
O que elimina a sua DAOFactory. Por sinal, como DAOImpl é a única implementação de IDAO, e interfaces não tem muito sentido se não forem para permitir múltiplas implementações, você poderia eliminar a IDAO também e transformar a sua DAOImpl apenas em SimpleDAO.
No entanto, caso queira manter o DAOFactory (por exeplo, você pretende fazer com que aquele if no começo possa variar), então voltando ao ponto 5, que tipo de tratamento você pode fazer caso não seja possível criar-se o DAO? Resposta: Nenhum. Qual é a razão de não ser possível criar-se o DAO? Resposta: Existe uma classe essencial faltando na aplicação. Portanto, neste caso aí, pode criar uma classe ConfigurationError, ApplicationAssemblyError ou algo parecido (observe que é Error, e não Exception). Então encapsule qualquer exceção capturada nestes pontos como causa deste seu Error, dê um throw no seu Error e esqueça. Esse é um exemplo típico de onde um Error é mais apropriado do que uma Exception simplesmente porque ele indica que há um problema fatal e irrecuperável na sua aplicação: Um pedaço dela está faltando ou no mínimo o arquivo properties dela (que você já eliminou) está faltando ou está inválido. Repetindo isso é só para o caso de você querer manter o DAOFactory, pois caso queira eliminá-lo, nada disso vai precisar existir. E caso queira eliminá-lo, é uma coisa a menos para complicar a arquitetura e uma coisa a menos para debuggar.
Bem, este artigo descreve bem o que é (na minha polêmica opinião) essa ideia de se ter DAOFactory:
http://www.marcoscintra.org/fabula_porcos.asp
Quanto ao ponto 3, o que é que o AbstractEntity te dá de bom? Pense bem antes de responder a esta pergunta, qual é o grande motivo de você ter esta classe, o que ela trás de bom? Na minha opinião, ela apenas economiza um pouco de trabalho de digitação nas subclasses. No entanto, acredito que você já deve ter visto sobre os problemas que herança te dá: A herança é um tipo bem forte de acoplamento. Trocar um pouco de trabalho de digitação por um tipo forte de acoplamento normalmente não é boa ideia. Quanto a questão da chave primária, embora seja desejável e seja boa ideia que elas sempre sejam ids simples autoincrementados, há algumas situações aonde isso não é desejado. Um exemplo de uma dessas situações é quando você tem uma tabela de relacionamento N-N entre duas outras tabelas e depois você decide acrescentar mais um atributo pertinente ao relacionamento, o que te força a transformá-la em outra tabela, no entanto você quer que a PK continue sendo as duas FKs das tabelas relacionadas.
Quanto ao ponto 8, O JUnit é uma ferramenta bem facinha de usar e requer zero de configuração. O Log4j é mais chatinho, mas recomendo usar o log4j por trás do slf4j. Dê uma pesquisada neles, inclua os que você quer no projeto, e daí voltamos aqui ao tópico.
Quanto ao ponto 6, deixo para o próximo post.
|
 |
|
|
nicolasls wrote:Ae Chulão...
Mtoooo obrigado cara!!!
Seu zip com o jar me ajudou mtoooo, fiquei umas 2hs procurando por esse jar na net e não achava!
Valew!
Ainda bem que PASSADOS 6 ANOS DA DISCUSSÃO ORIGINAL, este tópico ainda serve para ajudar alguém.
|
 |
|
|
danieldestro wrote:Acho que não vou precisar remover tópico mal educado ou de provocações, vou?
Tópico não. Mensagem talvez. Mas por enquanto não temos (eu acho) nada de errado aqui, apenas um usuário desafiando outro de uma forma até agora saudável.
|
 |
|
|
Servidores web devem ser inerentemente multi-threaded.
O motivo é que eles devem ser capazes de atender vários usuários ao mesmo tempo.
Cada requeisição é tratada por uma determinada Thread. Criar e destruir threads é uma coisa computacionalmente cara, por isso que os containers (incluindo o tomcat) já criam um número razoável de threads no começo e as deixam inativas: para evitar de ter que criá-las ou destruí-las em um momento inoportuno, e para poder reutilizá-las (evitando destruir para depois criar).
Idealmente, você programa de forma que os dados usados em uma thread não sejam compartilhados com outras threads, o que já te dá um multi-threading escalável e robusto. Os problemas começam a surgir quando uma thread tem que fazer alguma coisa que pode influenciar outra thread. É importante minimizar a necessidade de comunicação de threads.
Não há nada de errado por si só em criar threads auxiliares no servidor. No entanto, na maioria das vezes que isso ocorre, é porque o programador fez besteira, fez alguma gambiarra e/ou não sabe direito o que está fazendo, logo isto tende a ser um forte bad-smell.
|
 |
|
|
CintiaDR wrote:Uma interface só pode ter atributos públicos e estáticos, não? Então, por definição (por causa do estático), uma interface nunca vai ser mapeada para o banco.
É bem diferente do caso de superclasse.
Na verdade você pode mapear entidades também pelos pares de getters e setters. Não é este o motivo de não poder usar entidades mapeadas.
fabiofalci wrote:
ivansalvadori wrote:em JPA, as entidades são POJOS, e não implementam interfaces.
Na verdade pode implementar interface.
Ex:
Uma definição mais precisa seria de que apenas classes POJOs são mapeadas, o que não as proíbem de implementarem interfaces, mas as interfaces não são mapeadas.
|
 |
|
|
O JPA não suporta mapeamento objeto-relacional de interfaces, apenas de classes.
Existem vários problemas na implementação de baixo nível para um mapeamento assim que são difíceis de resolver. O principal destes problemas é que não existe o conceito de polimorfismo no modelo entidade-relacionamento (modelo este que é usado por quase todos os SGBDs). Desta forma, em um relacionamento entre duas tabelas, o banco de dados subjacente deve conhecer exatamente quais são as duas tabelas e elas nunca podem variar (ou seja, não é possível que em uma coluna X da tabela Y, um registro tenha a chave estrangeira apontando a tabela A e em outro registro para a tabela B), o que no lado do java significa efetivamente se amarrar a uma implementação. Para piorar este problema, entidades diferentes podem ter chaves de formatos completamente diferentes (inclusive compostas).
Existem algumas soluções parciais que atenuam este problema (mas não o eliminam). Uma delas é definir um mecanismo de herança que é mais ou menos suportado. No entanto, este mecanismo ainda tem fortes limitações. O modelo TABLE_PER_CLASS pode te induzir a ter queries gigantescas e lerdíssimas que crescem assustadoramente cada vez que você mapeia uma subclasse a mais (usam uma série de UNIONs), além de sacrificar consistência de chave estrangeira no banco de dados subjacente. O modelo SINGLE_TABLE te leva a um modelo sem normalização com o número de colunas crescendo cada vez que você cria uma subclasse, além de te impor que todos os campos das subclasses devem aceitar valores nulos. O modelo JOINED normalmente é o melhor, mas ele também pode te trazer alguns problemas e nem sempre você pode aplicá-lo. Se você fizer um select em uma lista cujo o tipo é a superclasse, vai quebrar a cara tanto com o TABLE_PER_CLASS quanto com o JOINED, pois será criada uma série de UNIONs, mas neste ponto o JOINED é um pouco melhor que o TABLE_PER_CLASS.
No entanto, ainda existem outros problemas de baixo nível além deste que eu te falei. Um destes outros problemas é que o JPA precisaria garantir que a implementação da interface, seja ela qual for, que estivesse devidamente mapeada no banco de dados para que pudesse ser persistida, coisa que na prática não é possível de garantir. A coisa mais próxima disso é a herança com JOINED.
O Hibernate tem, por fora do JPA, uma solução parcial para este problema que permite relacionar entidades com alguma outra entidade arbitrária sem que haja uma relação de herança entre essas entidades, usando as anotações @Any, @AnyMetaDef, @AnyMetaDefs e @ManyToAny, específicas do Hibernate. Nesta solução, você especifica todos os subtipos possíveis que um determinado objeto relacionado pode ter. No entanto, você tem que especificar de antemão todas as possíveis implementações, o que vai contra a ideia de se ter interfaces (aliás, nem sei se você mapeia uma interface ou se ele exige que seja simplesmente Object, mas neste caso você resolve com um simples cast). E o resultado não é dos melhores, sai algo muito parecido com o TABLE_PER_CLASS.
Resumindo: Esqueça, o que você quer fazer não é possível. A coisa mais próxima que tem é usar herança com JOINED ou TABLE_PER_CLASS, ou usar o @Any e/ou o @ManyToAny específicos do Hibernate. Ou então reestruture a sua aplicação de forma que não necessite de nenhum tipo de mapeamento de interfaces (o que normalmente é bastante doloroso).
|
 |
|
|
|
|