Sistema Web para Múltiplos Clientes

[quote=jonas.cant]O pessoal comentou bastante, e tem muita coisa que eu não entendi e talvez por hora eu não conseguiria implementar no sistema. Ainda sou um mero principiante em Java.
Só para esclarecimento, a minha situação hipotética é um TCC que estou desenvolvendo, não pretendo vender o sistema. Só quero desenvolver o TCC de uma forma que possa servir numa situação real.

Vamos ver se eu entendi:

Na primeira opção, para cada cliente que fosse comprar meu sistema eu teria que mudar as configurações de acesso ao banco e gerar um novo arquivo WAR que seria colocado no servidor que será mantido pelo próprio cliente.
Na segunda opção, o servidor seria mantido por minha “empresa” e todos clientes acessariam o sistema naquele servidor.

É isso?
[/quote]

Na mosca.

Bom, tendo em vista a complexidade de implementação do tal “multi-inquilino” em relação ao meu conhecimento atual, farei o sistema como se fosse vendê-lo e o cliente seria o mantenedor do servidor.
Só uma dúvida: meu cliente comprou o sistema e já está com o servidor pronto. Vou configurar o arquivo de conexão ao banco, gerar o WAR e implantar no servidor dele. Esse arquivo WAR não possibilita o cliente de alterar/visualizar o código fonte do sistema, correto? É seguro distribuir este arquivo?

Só precisa gerar o arquivo WAR uma vez na realidade.
Para isto, basta que você obtenha sua conexão com o banco de dados usando JNDI.
Aí basta que em cada servidor você configure o DataSource com o nome que você definir em suas configurações de acesso.

Ok. Vou ver como funciona utilizando JNDI, pois a princípio não fiz desta forma. Estou utilizando um arquivo xml de configuração e ali estou setando as configurações do banco de forma fixa.

[quote=jonas.cant]Bom, tendo em vista a complexidade de implementação do tal “multi-inquilino” em relação ao meu conhecimento atual, farei o sistema como se fosse vendê-lo e o cliente seria o mantenedor do servidor.
Só uma dúvida: meu cliente comprou o sistema e já está com o servidor pronto. Vou configurar o arquivo de conexão ao banco, gerar o WAR e implantar no servidor dele. Esse arquivo WAR não possibilita o cliente de alterar/visualizar o código fonte do sistema, correto? É seguro distribuir este arquivo?[/quote]

O war é apenas um zip. Ele pode ser descompactado, alterado, e recompactado. É seguro, mas não no sentido de “esconder o código”. Esqueça isso de “esconder o código”.

No cenário de um cliente por servidor (single-tenant), é o servidor que mantém a informação de onde está e qual é o banco de dados. Para isto vc precisa entender como funciona o JNDI e o JEE. O war não deve conter informações fixas sobre nenhuma configuração. Ele deve ler todas as configurações do JNDI do servidor. Desta forma, o mesmo war serve para diferentes servidores porque o que muda é o servidor, não o war. Por exemplo , se o war usasse um serviço de email, a configuração do serviço ficaria no servidor, nunca no war. O servidor JEE provê diversos serviços que o war pode usar , mas a configuração fica do lado do servidor.

Você precisa estudar mais sobre web em java, porque estão lhe faltando conceitos de base. Sem eles não tem como desenvolver uma arquitetura decente.

Eu, pessoalmente, gostaria muito mais de ver um TCC de multi-tenant do que de single-tenant, pelo simples facto que este ultimo cenário é o arroz com feijão e já está muito batido.

Concordo contigo, Sergio.
Pra muita coisa me falta a base, por isso estou aqui e até agora tem me ajudado.

Infelizmente nas faculdades (pelo menos na minha) o que é ensinado é menos que o básico pra desenvolver uma aplicação completa e decente. Eu escolhi Java Web por dois motivos:
1º Estou gostando bastante de Java;
2º Aprendizado.

Não pretendo fazer um “monstro” de TCC, meu objetivo principal é aprender. Mas enfim…

Então não é seguro eu distribuir o WAR já que o cliente pode alterar o código e compilar novamente? Tem alguma outra forma?

[quote=jonas.cant]Concordo contigo, Sergio.
Pra muita coisa me falta a base, por isso estou aqui e até agora tem me ajudado.

Infelizmente nas faculdades (pelo menos na minha) o que é ensinado é menos que o básico pra desenvolver uma aplicação completa e decente. Eu escolhi Java Web por dois motivos:
1º Estou gostando bastante de Java;
2º Aprendizado.

Não pretendo fazer um “monstro” de TCC, meu objetivo principal é aprender. Mas enfim…

Então não é seguro eu distribuir o WAR já que o cliente pode alterar o código e compilar novamente? Tem alguma outra forma?

[/quote]

pro seu TCC é seguro.
pro mundo real não.

O que rola: seu custo de atualização das máquinas clientes no mundo real fica caro.
Imagine ter de atualizar servidor por servidor.

Entendi. A questão da atualização realmente fica praticamente inviável se por exemplo a empresa tem 500 clientes. Sem dúvidas o uso de multi-inquilino seria a melhor opção. Quem sabe até lá eu aprenda a implementar isto. :smiley:
Se alguém tiver algum material bom sobre como implementar o modelo multi-inquilino, fique à vontade.

[quote=jonas.cant]Entendi. A questão da atualização realmente fica praticamente inviável se por exemplo a empresa tem 500 clientes. Sem dúvidas o uso de multi-inquilino seria a melhor opção. Quem sabe até lá eu aprenda a implementar isto. :smiley:
Se alguém tiver algum material bom sobre como implementar o modelo multi-inquilino, fique à vontade.[/quote]

O conceito é simples, depois vc tem que o encaixar nas ferramentas ou implementar do zero.
O conceito é que o sistema tem uma variável chamada TenantID. Esta variável identifica o cliente ( o inquilino). Ela pode esta associada ao login do usuário, ou url de acesso, a coockies, ou a um combinação de todos dependendo como o acesso ao sistema se dá. Normalmente se dá por uma URL dedicada para cada cliente, ( e neste caso cada cliente pode ter um look e layout diferente) ou uma mesma página com a cada da sua empresa que depois do login manda para o sistema customizado do cliente.
Seja como for, vc detecta o tenantID e o usa em todas as invocações (é preciso uma arquitetura e um design amigável para isto). Portanto, em todos os pontos do sistema vc sabe quem está acessando (quem é o user) e em que ambiente ele está ( quem é o inquilino). Para persistencia existem diferentes tecnicas ( que o hibernate implementa). A primeira mais obvia é ter o tenantID como chave em todas as tabelas. A segunda é ter um schema por tennatId num mesmo banco de dados ( para os bancos de dados que suportam isto) e a ultima é ter um banco por tennatID. A primeira é melhor se existem dados ou serviços que ganham sendo partilhados (estatisticas por exemplo), a ultima garante segregação máxima e que nunca nenhum tenant tem o risco de acessar coisas do outro.

Não tem muito mais que isto. O resto é detalhes de implementação, considerações de design e tentar fazer de uma forma que o sistema sabe o tenanat, mas o programador quase não tenha que saber que isso existe. De forma que a programação seja o mais próximo possivel do single-tennat.

Interessante… não parece ser o bicho de sete cabeças.
Se eu fosse implementar esse modelo, com certeza eu faria com que cada inquilino tivesse um banco de dados próprio.

[quote=jonas.cant]Interessante… não parece ser o bicho de sete cabeças.
Se eu fosse implementar esse modelo, com certeza eu faria com que cada inquilino tivesse um banco de dados próprio.[/quote]

É… só que como já foi dito aqui, isso torna as coisas mais caras para si. O que é meio obvio pois mais segurança normalmente sempre significa mais caro.
Também tem relação com a elasticidade, pois nesse modelo o servidor de nuvem ( este cenário é para ser usado em nuvem) deve criar uma banco de dados novo , mas ele pode não ter a informação de qual criar. As coisas ficam um pouco mais complexas na prática neste cenários. O cenários mais simples é ter o id por tabela. O ideal é realmente usar um schema por tenant, não tem as dores de cabeça de criar várias bancos de dados, nem os problemas de dados misturados, contudo todo o mundo está no mesmo banco. Em tese é o trade-off mais simples, mas na realidade nenhum dos três é o melhor em todos os requisitos, por isso mesmo, existem três , :lol:

A analise em si do trade-off já dá pano para mangas dependendo dos vários cenários de deploy , constrangimentos de tempo e dinheiro e diretivas que a “sua emprea ficiticia” gostaria de seguir. Por exemplo, se seus clientes têm como pagar um banco para cada um, então esta opção é a melhor pois o custo está coberto. Caso aponte clientes mais modestos, uma das outras opções terá que servir, ou o seu modelo de negocio deve gerar fundos suficientes para cobrir os custos.

[quote=jonas.cant]Interessante… não parece ser o bicho de sete cabeças.
Se eu fosse implementar esse modelo, com certeza eu faria com que cada inquilino tivesse um banco de dados próprio.[/quote]

Vai por mim, são no mínimo umas 9 cabeças aí. :slight_smile:

Hehehe… pois é, as vezes sou bastante otimista. :smiley:
Só acho muito “esquisito” vários clientes no mesmo banco de dados, separando os dados apenas por ID… até digo que se isso já significa modelo multi-inquilino não é nada difícil.
Eu não vejo isso como uma boa prática, apesar de que pode ser bem mais simples de manter. Pensando na questão da segurança da informação e na performance do sistema (pensa ter 500 clientes tudo no mesmo bando de dados) eu creio que deixaria a desejar.

[quote=jonas.cant]Hehehe… pois é, as vezes sou bastante otimista. :smiley:
Só acho muito “esquisito” vários clientes no mesmo banco de dados, separando os dados apenas por ID… até digo que se isso já significa modelo multi-inquilino não é nada difícil.
Eu não vejo isso como uma boa prática, apesar de que pode ser bem mais simples de manter. Pensando na questão da segurança da informação e na performance do sistema (pensa ter 500 clientes tudo no mesmo bando de dados) eu creio que deixaria a desejar.[/quote]

Quer ler algo muito bacana sobre este problema? Da uma pesquisada no Google nos artigos publicados pela equipe da SalesForce.com
Eles inovaram bastante nesta área, e passaram por situações como esta.

No caso de tabelas compartilhadas por múltiplos clientes, uma alternativa massa é o particionamento da tabela: cada usuário teria a sua própria partição, o que garantiria a segurança e também a performance (parte da perforamcne pelo menos) nas consultas.

Particionamento de tabela? :shock:
Confesso que é a primeira vez que leio isso. Vou pesquisar mais…

Oi Jonas, sim.

Tem bancos de dados que te permitem particionar a tabela. Este é um procedimento que consiste em armazenar a tabela em “pedaços”, que não necessáriamente estão no mesmo servidor.
Você define isto usando uma coluna específica para identificar a partição. NO caso, o “tenant_id” pode ser aplicado.

Aí, neste caso, toda consulta que tenant_id for 1, por exemplo, busca na partição 1, 2, partição 2, e por aí vai.
A grossíssimo modo é isto.

Muito interessante.
Bastante coisa pra eu pesquisar. Mas vamos lá…

desenvolvi um sistema de fidelização que é utilizado para vários clientes,
cada cliente possui sua base, mas o WAR é apenas um.
Criei um base para armazenar as informações de servidor de cada cliente, ai quando é realizado o login na aplicação o sistema consulta essa base e altera as configurações do hibernate dinamicamente…

            AnnotationConfiguration cfg = new AnnotationConfiguration();
		cfg.configure()
		.setProperty("hibernate.connection.url", "jdbc:mysql://127.0.0.1:3306/cliente1")
		.setProperty("hibernate.connection.username","user")
		.setProperty("hibernate.connection.password","pass");

		sessionfactory = cfg.buildSessionFactory();

[quote=build_successful]desenvolvi um sistema de fidelização que é utilizado para vários clientes,
cada cliente possui sua base, mas o WAR é apenas um.
Criei um base para armazenar as informações de servidor de cada cliente, ai quando é realizado o login na aplicação o sistema consulta essa base e altera as configurações do hibernate dinamicamente…

[code]
AnnotationConfiguration cfg = new AnnotationConfiguration();
cfg.configure()
.setProperty(“hibernate.connection.url”, “jdbc:mysql://127.0.0.1:3306/cliente1”)
.setProperty(“hibernate.connection.username”,“user”)
.setProperty(“hibernate.connection.password”,“pass”);

	sessionfactory = cfg.buildSessionFactory();

[/code][/quote]

Opa, da pra resolver este problema de forma até mais simples.
Basta que a sua conexão com o banco de dados seja obtida via JNDI.
Aí nem sua string de conexão precisa mudar. Basta você cadastrar um datasource no servidor com o nome que você programou no seu sistema.

[quote=kicolobo][quote=build_successful]desenvolvi um sistema de fidelização que é utilizado para vários clientes,
cada cliente possui sua base, mas o WAR é apenas um.
Criei um base para armazenar as informações de servidor de cada cliente, ai quando é realizado o login na aplicação o sistema consulta essa base e altera as configurações do hibernate dinamicamente…

[code]
AnnotationConfiguration cfg = new AnnotationConfiguration();
cfg.configure()
.setProperty(“hibernate.connection.url”, “jdbc:mysql://127.0.0.1:3306/cliente1”)
.setProperty(“hibernate.connection.username”,“user”)
.setProperty(“hibernate.connection.password”,“pass”);

	sessionfactory = cfg.buildSessionFactory();

[/code][/quote]

Opa, da pra resolver este problema de forma até mais simples.
Basta que a sua conexão com o banco de dados seja obtida via JNDI.
Aí nem sua string de conexão precisa mudar. Basta você cadastrar um datasource no servidor com o nome que você programou no seu sistema.[/quote]Issé mesmo. Tava até escrevendo aqui. [=

Veja pesquise como funciona datasource do seu servidor, aí basta referir ao datasource.