Pergunta

Estou desenvolvendo uma aplicação web java servlet que gerencia informações de várias bases de dados (todos estruturalmente o mesmo) cada um correspondendo a um "negócio" diferente. O usuário seleciona "o negócio atual" que é armazenado na sessão e o aplicativo pode exibir ou modificar esse "negócio atual".

Eu gostaria de usar tomcat recursos de forma dinâmica para ter acesso a estas empresas que utilizam jndi. Desta forma eu posso usar as tags JSTL SQL ou pesquisas de contexto em servlets. Eu não posso definir cada recurso no arquivo web.xml, porque eles são armazenados em uma tabela SQL. O resultado final é para ser capaz de escrever jsp simples que tem linhas como estas:

<%@ taglib uri="http://java.sun.com/jstl/sql" prefix="sql" %>

<sql:query var = "users" dataSource="sources/${sessionScope.currentBusiness}">
  select id, firstName, lastName FROM user
</sql:query>

ou servlets que podem ter linhas como estes

String request.getSession().getAttribute("currentBusiness");

Context initial = new InitialContext();
Context context = (Context) initial.lookup("java:comp/env");
DataSource source = (DataSource) context.lookup("sources/" + currentBusiness);

onde posso obter a fonte de dados correto para o "negócio atual".

Eu experimentei com a escrever as minhas próprias ObjectFactories derivados de javax.naming.spi.ObjectFactory sem sucesso. Os ponteiros sobre como fazer isso facilmente?

Foi útil?

Solução

Eu finalmente resolvido para a solução seguinte que consiste em um SessionListener e um Servlet que o trabalho da seguinte forma. O SessionListener tem a seguinte forma:

public class SessionListener implements HttpSessionListener {

  public void sessionCreated(HttpSessionEvent event) {

    HttpSession session = event.getSession();

    // get list of possible data sources available to this session
    List<DataSource> sources = new ArrayList<DataSource>();
    ... code to get the available sources

    // get the current data source
    DataSource source = null;
    ... code to get the current source                               
    source = sources.get(0); // for example

    // setup the session attributes
    session.setAttribute("availableSources", sources);
    session.setAttribute("currentSource", source); 

  }

}

Sempre que um usuário faz login e uma sessão é criada, a lista de DataSources disponíveis, e o atual, são colocados na sessão. Isto é feito no nível da sessão, porque DataSources depender do login do usuário. Ele agora é possível ter acesso a eles de dentro do aplicativo. Para alterar o atual DataSource eu criei um Servlet com esta versão simplificada:

public abstract class BoxletServlet extends HttpServlet {

  protected void doGet(HttpServletRequest request, HttpServletResponse response) 
    throws ServletException, IOException {

    HttpSession session = request.getSession(true);
    String s = request.getParameter("source");

    // based on 's' choose from the available DataSource
    List<DataSource> sources = (List<DataSource>) session.getParameter("availableSources");
    Source source = chooseFrom(sources, s);                                                       
    session.setParameter("currentSource", source);          

    // forward to a page saying that the DataSource changed

  }

}

Com esta implementação, agora é possível criar as seguintes jsps:

<%@ taglib uri="http://java.sun.com/jstl/sql" prefix="sql" %>

<sql:query var = "users" dataSource="${sessionScope.currentSource}">
  select id, firstName, lastName FROM user
</sql:query>

Espero que ajude alguém.

Outras dicas

Criar as fontes de dados em um ServletContextListener e colocá-los no ServletContext .

Esta abordagem irá certamente "trabalho", mas a noção de um banco de dados separado, idêntico para cada negócio parece errado para mim. Certamente ser capaz de delinear um lugar de negócios no esquema parece possível. Separá-los dessa forma exige um novo banco de dados por negócios, onde um esquema exigiria apenas um novo identificador de empresa.

Eu também diria que qualquer possibilidade de mineração de dados cross-business está perdido, a menos que os dados ETL de bancos de dados separados em um cubo dimensional para relatórios ad hoc e consultas.

E JSTL marcas só deve ser usado nas mais simples aplicações web. Você deixar-se abrir para a possibilidade de ataques de injeção SQL quando você renunciar a validação em uma camada intermediária.

UPDATE:

Você tem que declarar recursos em seu web.xml AFAIK, por isso sempre que você tem um novo banco de dados que você tem que parar o aplicativo, configurar a nova fonte de JNDI, e reinicie o Tomcat. Espero que esteja em cluster, porque todos os clientes anteriores será afetado pelo aplicativo a ser baixo cada vez que você adicionar um novo negócio / banco de dados.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top