Serviço windows com java

Olá galera, sou iniciante na linguagem Java e durante meus estudos gostaria de já embarcar em um projeto, pois assim acredito que terei melhor aproveitamente durante a fase de aprendizado. Partindo deste ponto, decidi criar um “programa” que detalharei abaixo e gostaria de obter a opinião dos amigos do forum para saber se é realmente viável.

Na verdade, o programa terá que funcionar como um serviço no windows e não terá interface com o usuário. É possível criar um serviço no Windows na linguagem Java?

Função:

  • Sempre que a máquina do cliente for conectada a internet, o programa java (utilizando a biblioteca HTMLUNIT) acessará um determinado site, recolherá algumas informações do mesmo e alimentará um BD interno com estes dados. Com BD interno, quero dizer que cada máquina onde este programa estiver possuirá seu próprio banco local, acredito que isso seja possível de ser feito.

  • O sistema realizará a ação (como indicado acima) sempre que a máquina cliente se conecte à internet (ou renove o ip) ou caso o tempo entre a última ação supere 24 horas, mesmo que o IP permaneça o mesmo. O motivo para que isso aconteça é porque o site a ser acessado não pode receber frequentes acessos de um mesmo endereço IP.
    Existe alguma maneira de disparar a ação de um serviço no Windows conforme o modo aqui descrito?

  • Esse serviço deverá estar presente em muitas máquinas, portanto preciso de um meio rápido para inseri-lo no Windows. Andei pesquisando e descobri que podemos criar um .bat para fazer esta tarefa, sendo necessário apenas executar o arquivo em cada máquina em que se deseja criar o serviço. É possível?

Bem, a princípio é somente isto. Abraços e obrigado desde já!

Se você tivesse o skill para fazer o mesmo programa em C++ seria mais simples fazer a parte de checar se há conexão com a Internet (é que há um probleminha, que antigamente era mais sério: às vezes, o simples fato de você tentar se conectar a um endereço Internet forçava a discagem de uma conexão, o que provavelmente não é mais o seu problema. A parte de pegar dados da Internet também é simples (não precisaria usar algo tão pesado quanto o htmlunit. )

Fazer o mesmo programa em Java é muito intrusivo (tanto é que o pessoal da Oracle tem um serviço de atualização do Java que não é feito em Java), porque o Java gasta uma quantidade absurda de memória para um serviço que deve só pegar meia dúzia de bytes da Internet de vez em quando. Além disso, fica muito pesado em termos de instalação (na prática é sempre melhor distribuir uma máquina virtual Java completa, o que gasta muitos bytes também na hora da instalação).

[quote=entanglement]Se você tivesse o skill para fazer o mesmo programa em C++ seria mais simples fazer a parte de checar se há conexão com a Internet (é que há um probleminha, que antigamente era mais sério: às vezes, o simples fato de você tentar se conectar a um endereço Internet forçava a discagem de uma conexão, o que provavelmente não é mais o seu problema. A parte de pegar dados da Internet também é simples (não precisaria usar algo tão pesado quanto o htmlunit. )

Fazer o mesmo programa em Java é muito intrusivo (tanto é que o pessoal da Oracle tem um serviço de atualização do Java que não é feito em Java), porque o Java gasta uma quantidade absurda de memória para um serviço que deve só pegar meia dúzia de bytes da Internet de vez em quando. Além disso, fica muito pesado em termos de instalação (na prática é sempre melhor distribuir uma máquina virtual Java completa, o que gasta muitos bytes também na hora da instalação). [/quote]

Entendo o que quer dizer. Vamos à alguns pontos:

  • O motivo pelo qual eu pensei em utilizar o HTMLUNIT é porque eu precisaria acessar o site e realizar algumas ações (como um usuário humano faria), bem semelhante as macros que muitos utilizam em navegadores. Não sei se até aqui daria para ser feito fora do HTMLUNIT. Mas ainda existe um outro problema, preciso simular um navegador. Não sei se existe biblioteca mais leve e que cumpra a mesma função.

  • Pelo o que andei lendo, uma alternativa seria fazer um serviço que inicie com o Windows e este serviço ficaria rodando infinitamente por tráz da máquina, verificando a conexão com a internet, recolhendo o ip caso esteja conectado, verificando se o ip já fez o acesso ao site dentro de 24 horas (estas informações estariam no banco que citei), visitando o site caso seja necessário e registrando os dados recolhidos em outra tabela do banco. Ao chegar ao final, ele iniciaria tudo novamente.

Já que a consulta ao banco local evita com que ele visite o site desnecessariamente, o procedimento acima pouco influenciaria na velocidade da conexão com a internet, porém em termos de processamento parece não ser o mais adequado. Por este motivo fiquei interessado em saber se existe uma maneira do próprio sistema chamar o serviço quando o mesmo for necessário, ou seja, de acordo com as regras que estabeleci.

Não descarto o uso de outra linguagem, porém preciso que ela me forneça as ferramentas (bibliotecas) que preciso para a execução deste projeto.

De fato, se você precisa de acessar um site e efetuar uma navegação complexa, é realmente melhor você usar algo pronto como o httpunit (já que usar as APIs do Windows que obtém dados da Internet - WinHTTP ( http://msdn.microsoft.com/en-us/library/windows/desktop/aa382925(v=vs.85).aspx ) é meio complicado, a menos que você tenha um acesso mais simples (como um web service ou uma página boba, sem autenticação) a esse site.

Bem, considerando que o programa será feito em Java e que já tenho em mente a bilbioteca a ser utilizada. Minha dúvida maior está ligada em como eu o escreveria a fim de funcionar como um serviço.

Seria como descrevi anteriormente? Iniciando com o sistema operacional e rodando em looping verificando a conexão com a internet? Caso seja deste modo, estive pensando em programar algo para que após a primeira execução ele fique um tempo parado (1 hora, por exemplo), para ao menos reduzir o consumo de processamento, existe algo no java que proporcione isso?

Use um java.util.Timer para disparar algo periodicamente.

Para deixar um programa como serviço, pode tentar o Java Service Wrapper ( http://wrapper.tanukisoftware.com/doc/english/download.jsp ) ou o Apache Commons Daemon ( http://commons.apache.org/daemon/ ) ou o JavaService ( http://forge.ow2.org/projects/javaservice ). Veja qual deles se adequa melhor a suas necessidades.

[quote=entanglement]Use um java.util.Timer para disparar algo periodicamente.

Para deixar um programa como serviço, pode tentar o Java Service Wrapper ( http://wrapper.tanukisoftware.com/doc/english/download.jsp ) ou o Apache Commons Daemon ( http://commons.apache.org/daemon/ ) ou o JavaService ( http://forge.ow2.org/projects/javaservice ). Veja qual deles se adequa melhor a suas necessidades.
[/quote]

Obrigado pela ajuda, quanto ao banco para salvar os dados, vou utilizar um banco embedded SQLite.

Só lembrando que o SQLite requer código nativo, então é aconselhável você realmente empacotar uma versão da JRE (de 32 bits, provavelmente) com seu serviço, para evitar que você tente rodar um código nativo de 32 em um Java de 64 bits ou vice-versa. Eu já apanhei muito com isso (não saber exatamente qual versão do Java está instalada na máquina do usuário).

Eu aconselharia a usar algum programa de geração de instaladores, já que você precisa fazer várias coisas.

a) Instalar um serviço no Windows.
b) Criar um usuário de serviço, caso necessário (se ele precisar acessar o proxy, por exemplo, e se seu proxy requer autenticação de usuário do Windows - o que é comum quando se usa o MS ISA Server - você precisará instalar o seu serviço sob um determinado usuário do Windows)
c) Instalar a versão da JRE necessária para rodar seu programa Java.

(Em particular sempre acho que as coisas aparentemente mais simples têm um monte de detalhes complicados, e é por isso que há os famosos “já consegui fazer 90%” - os restantes 10% é que consomem 99% do seu tempo :frowning: )

[quote=entanglement]Eu aconselharia a usar algum programa de geração de instaladores, já que você precisa fazer várias coisas.

a) Instalar um serviço no Windows.
b) Criar um usuário de serviço, caso necessário (se ele precisar acessar o proxy, por exemplo, e se seu proxy requer autenticação de usuário do Windows - o que é comum quando se usa o MS ISA Server - você precisará instalar o seu serviço sob um determinado usuário do Windows)
c) Instalar a versão da JRE necessária para rodar seu programa Java.

(Em particular sempre acho que as coisas aparentemente mais simples têm um monte de detalhes complicados, e é por isso que há os famosos “já consegui fazer 90%” - os restantes 10% é que consomem 99% do seu tempo :frowning: )[/quote]

ushashua, obrigado pelas palavras encorajadoras… Você me atentou para um detalhe para o qual não dei atenção, como a probabilidade do usuário estar utilizando um proxy.

Vejo que terei uma longa caminhada a frente, estou me esforçando ao máximo para não ficar boiando nas dicas que você me passou, rsrs.

Realmente não tenho como saber qual versão da JRE estará na máquina cliente, mas pensei que o Java 64 bits fosse capaz de rodar o 32 bits. Neste caso eu teria que substituir o JRE da máquina cliente?

Não é isso.
O seu problema é com código nativo (do SQLite).
Se você vai usar código nativo (JNI), é necessário que o JNI que você vai usar seja compilado para a mesma versão (32 ou 64 bits ) que a JVM / JRE que você está usando.

Além disso, você pode ter N versões de JRE em uma mesma máquina. Em minha máquina, em casa, por exemplo, tenho 6 - Java 6, 7 e 8, em 32 e 64 bits.

Entanglement,

Um amigo me sugeriu criar este serviço em C#.NET, segundo ele seria muito mais adequado do que em Java. Pesquisando na internet, descobri uma alternativa ao HtmlUnit para esta linguagem, trata-se do Selenium que além de possuir características semelhantes, possui uma API para o C#. O que acha disso?

De fato, é bem mais econômico em termos de recursos criar um serviço em C#, sem contar que a maior parte das APIs do Windows é muito mais fácil chamar a partir do C#.
Só tomar um pouco de cuidado com a versão do framework que será seu “target”. Dependendo, pode ser que a versão do .NET Framework que você escolher não esteja instalada nas máquinas clientes e você terá de incluir o instalador do framework junto com o instalador de seu serviço.

[quote=entanglement]De fato, é bem mais econômico em termos de recursos criar um serviço em C#, sem contar que a maior parte das APIs do Windows é muito mais fácil chamar a partir do C#.
Só tomar um pouco de cuidado com a versão do framework que será seu “target”. Dependendo, pode ser que a versão do .NET Framework que você escolher não esteja instalada nas máquinas clientes e você terá de incluir o instalador do framework junto com o instalador de seu serviço. [/quote]

Falando em instalador de serviço, existe alguma maneira de criar um executável (ou algo parecido) que instale o serviço na máquina de forma rápida? Minha ideia era bastar apenas executar um arquivo na máquina e o serviço já seria instalado.

Pois bem, o Visual Studio tem (ou tinha) um gerador de instaladores. Veja se isso está incluído na sua versão (se for a versão gratuita temo que não esteja disponível).

Se está fazendo algo para rodar só no Windows pelo amor de Deus esqueça Java mesmo. Segue exemplo: http://programandodotnet.wordpress.com/2010/07/18/criando-um-windows-service/