gerenciamento.xml 15.7 KB
<?xml version='1.0' encoding="utf-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" []>
<chapter id="gerenciamento">

	<title>Monitoração e Gerenciamento de Recursos</title>
	
	<section>
		<title>Por que monitorar e gerenciar aplicações</title>
		
		<para>Ao implantar um sistema para produção, muitas vezes é necessário monitorar aspectos sobre o funcionamento desse sistema. Quanta memória
		ele está utilizando? Qual o pico de MIPS utilizados? Quantas sessões estão autenticadas no momento?</para>
		
		<para>Além de monitorar um sistema, as vezes é necessário gerenciá-lo alterando aspectos de seu comportamento. Se o sistema está implantado em um
		servidor alugado, talvez seja necessário ajustar o uso de MIPS para reduzir custos ou talvez deseje-se solicitar que o sistema limpe dados de sessão
		de autenticação abandonados por usuários que desligaram suas estações sem efetuar "logoff".</para>
		
		<para>Para esse fim existem diversas tecnologias que permitem ao desenvolvedor expor aspectos monitoráveis e gerenciáves de seu sistema
		para clientes de gerenciamento. Exemplos dessas tecnologias incluem o <emphasis>Simple Network Management Protocol</emphasis> (SNMP) e o
		<emphasis>Java Management Extension</emphasis> (JMX).</para>
		
		<para>O <emphasis>Demoiselle Framework</emphasis> dispõe de uma série de ferramentas para nivelar
		o conhecimento do desenvolvedor e facilitar o uso e integraçao de várias tecnologias de gerenciamento e 
		monitoração. Através de seu uso o desenvolvedor pode facilmente integrar tais tecnologias, despreocupando-se 
		com detalhes de implementação de cada uma delas.</para>
	</section>
	
	<section>
		<title>Introdução ao mecanismo</title>
		
		<para>Para expor aspectos monitoráveis da sua aplicação, o primeiro passo é criar uma interface contendo os atributos monitoráveis e as operações
		de gerenciamento que serão expostas para clientes de gerenciamento. Isso é feito através de uma simples classe Java (<emphasis>ou POJO</emphasis>)
		anotada com o estereótipo <code>@ManagementController</code>.</para>
		
		<programlisting role="JAVA"><![CDATA[
@ManagementController
public class GerenciadorUsuarios]]></programlisting>
		
		<para>Essa anotação é suficiente para o mecanismo de gerenciamento descobrir sua classe e disponibilizá-la para ser monitorada e gerenciada.</para>
		
		<para>Contudo, a simples anotação acima não informa ao mecanismo quais aspectos da classe serão expostos. Por padrão, um <emphasis>Management Controller</emphasis>
		não expõe nenhum aspecto seu. Para selecionar quais aspectos serão expostos usamos as anotações
		<emphasis>@ManagedProperty</emphasis> e <emphasis>@ManagedOperation</emphasis>. Além disso outras anotações podem ser usadas para personalizar o funcionamento
		de classes anotadas com <code>@ManagementController</code>.</para>
		
		<informaltable>
			<tgroup cols="3" rowsep="1" colsep="1">
				<thead>
					<row>
						<entry>Anotação</entry>
						<entry>Descrição</entry>
						<entry>Atributos</entry>
					</row>
				</thead>
			
				<tbody>
					<row valign="top">
						<entry>
							<emphasis role="BOLD">@ManagedProperty</emphasis>
						</entry>
						
						<entry>
							<para>Marca um atributo na classe como uma propriedade gerenciada, significando que clientes externos podem ler e/ou escrever valores nesses atributos.</para>
							<para>Um atributo marcado pode estar disponível para leitura e/ou escrita. Por padrão, o que determina a visibilidade de um atributo
							marcado é a presença dos métodos <emphasis>getAtributo</emphasis> e <emphasis>setAtributo</emphasis>, respectivamente disponibilizando o atributo
							para leitura e escrita.</para>
							<para>Para sobrescrever esse comportamento existe na anotação <emphasis role="BOLD">@ManagedProperty</emphasis> o atributo <emphasis>accessLevel</emphasis>.
							Com ele é possível criar um atributo apenas para leitura, mas que contenha um método <emphasis>set</emphasis>. O contrário também é possível.</para>
						</entry>
						
						<entry>
							<itemizedlist>
								<listitem><emphasis role="BOLD">description</emphasis>: Um texto descritivo documentando o propósito da propriedade.</listitem>
								<listitem><emphasis role="BOLD">accessLevel</emphasis>: Sobrescreve o nível padrão de acesso de uma propriedade. Os valores possíveis são
								READ_ONLY, WRITE_ONLY e DEFAULT, que significa que a presença de métodos <emphasis>get</emphasis> e <emphasis>set</emphasis> vai determinar o nível de acesso.</listitem>
							</itemizedlist>
						</entry>
					</row>
					
					<row valign="top">
						<entry>
							<emphasis role="BOLD">@ManagedOperation</emphasis>
						</entry>
						
						<entry>
							<para>Marca um método da classe gerenciada como uma operação, o que significa que clientes externos podem invocar esse método remotamente.</para>
							<para>Operações gerenciadas normalmente são criadas para executar intervenções em um sistema já em execução. Por exemplo, é possível criar uma
							operação que, ao ser invocada, destrua todas as seções abertas no servidor e não utilizadas nos últimos 30 minutos.</para>
						</entry>
						
						<entry>
							<itemizedlist>
								<listitem><emphasis role="BOLD">description</emphasis>: Um texto descritivo documentando o propósito da operação.</listitem>
								<listitem><emphasis role="BOLD">type</emphasis>: Documenta o propósito da operação. <emphasis>ACTION</emphasis> informa que a operação modificará
								o sistema de alguma forma. <emphasis>INFO</emphasis> diz que a operação coletará e retornará informações sobre o sistema. <emphasis>ACTION_INFO</emphasis> 
								informa que a operação modificará o sistema de alguma forma e retornará informações sobre o resultado. <emphasis>UNKNOWN</emphasis> é o padrão
								e significa que o resultado da execução da operação é desconhecido.</listitem>
							</itemizedlist>
						</entry>
					</row>
					
					<row valign="top">
						<entry>
							<emphasis role="BOLD">@OperationParameter</emphasis>
						</entry>
						
						<entry>
							<para>Esta anotação opcional pode ser usada para cada parâmetro de um método anotado com <emphasis role="BOLD">@ManagedOperation</emphasis>.</para>
							
							<para>Ele permite detalhar melhor parâmetros em uma operação gerenciada. O efeito desta anotação é dependente da
							tecnologia utilizada para comunicação entre cliente e servidor. Na maioria das tecnologias, essa anotação meramente permite ao cliente
							exibir informações sobre cada parâmetro: nome, tipo e descrição.</para>
						</entry>
						
						<entry>
							<itemizedlist>
								<listitem><emphasis role="BOLD">name</emphasis>: O nome do parâmetro quando exibido para clientes.</listitem>
								<listitem><emphasis role="BOLD">description</emphasis>: Um texto descritivo documentando o propósito do parâmetro.</listitem>
							</itemizedlist>
						</entry>
					</row>
				</tbody>
			</tgroup>
		</informaltable>
		
	</section>
	
	
	
	<section>
		<title>Expondo aspectos de sua aplicação para monitoração</title>
		
		<para>Uma vez que uma classe esteja anotada com <emphasis>@ManagementController</emphasis> e seus atributos e operações estejam expostos, a classe está pronta para
		ser monitorada.</para>
		
		<para>Suponha que a aplicação deseje expor o número de usuários que efetuaram login. A operação de <emphasis>login</emphasis> será processada em
		uma classe de negócio <emphasis>ControleAcesso</emphasis>. Vamos supor também que existe uma classe chamada <emphasis>MonitorLogin</emphasis> responsável
		por expor o número de usuários que efetuaram login no sistema.</para>
		
		<programlisting role="JAVA"><![CDATA[
@BusinessController
public class ControleAcesso{

  @Inject
  private MonitorLogin monitorLogin;

  public boolean efetuarLogin(String usuario , String senha){
    // codigo de login
    monitorLogin.setContadorLogin( monitorLogin.getContadorLogin() + 1 );
  }
}]]></programlisting>

	<programlisting role="JAVA"><![CDATA[
@ManagementController
public class MonitorLogin{

  @ManagedProperty
  private int contadorLogin;

  @ManagedOperation
  public void setContadorLogin(int qtdUsuarioLogados){
    contadorLogin = qtdUsuarioLogados;
  }

  @ManagedOperation
  public int getContatorLogin(){
    return contadorLogin;
  }
}]]></programlisting>
		
		<para>Como é possível ver, classes anotadas com <emphasis>@ManagementController</emphasis> podem ser injetadas em qualquer ponto do código. Valores definidos
		para seus atributos retêm seu estado, então um cliente que acesse remotamente o sistema e monitore o valor do atributo <emphasis>contadorLogin</emphasis> verá
		a quantidade de logins efetuados no momento da consulta.</para>
		
		<section>
			<title>Enviando notificações da aplicação</title>
			
			<para>
				É comum que aplicações monitoradas permaneçam em estado de espera - é função do cliente de monitoração acessar a aplicação e obter
				as informações necessárias. No entanto existem casos onde é necessário que a aplicação comunique clientes de eventos ocorridos no sistema. Um exemplo é um monitor
				de espaço em disco que envia um alerta quando esse espaço for menor que 20% do total. 
			</para>
			
			<para>
				Para essa funcionalidade o <emphasis>Demoiselle Framework</emphasis> disponibiliza o utilitário <emphasis>NotificationManager</emphasis>, que
				pode ser injetado em sua aplicação a qualquer momento para notificar clientes externos de eventos importantes. 
			</para>
			
			<para>Considere o exemplo abaixo:</para>
			
			<programlisting role="JAVA"><![CDATA[
public class DiskWritter{

  @Inject
  private NotificationManager notificationManager;

  public void writeFile(byte[] data , File fileToWrite){
    // ... implementação da escrita de arquivo
    
    if (fileToWrite.getUsableSpace() / (float)fileToWrite.getTotalSpace() <= 0.2f){
    	Notification notification = new GenericNotification("O espaço disponível no disco é inferior a 20% do total");
    	notificationManager.sendNotification( notification );
    }
  }
}]]></programlisting>

			<para>
				Como é possível ver no exemplo, o utilitário <emphasis>NotificationManager</emphasis> é usado para enviar notificações em decorrência
				de eventos ocorridos na sua aplicação. O uso mais comum é notificar avisos ou problemas para que ações sejam tomadas, mas é possível também
				usar essa técnica para tomar ações preventivas ou informativas - uma notificação que o backup noturno foi feito com sucesso por exemplo.
			</para>
			
			<para>
				A interface <emphasis>Notification</emphasis> é a base das notificações enviadas e possui apenas um método:
				<emphasis>Object getMessage()</emphasis>. A API de monitoração não força o tipo específico da mensagem e usualmente essa mensagem
				será uma <emphasis>String</emphasis> (como no exemplo acima), mas algumas extensões podem utilizar tipos específicos de mensagem
				capazes de carregar mais informações.
			</para>
			
			<para>
				O <emphasis>demoiselle-core</emphasis> disponibiliza por padrão o tipo concreto de notificação <emphasis>GenericNotification</emphasis> - uma
				implementação direta da interface <emphasis>Notification</emphasis> que permite definir a mensagem a ser retornada por <emphasis>getMessage()</emphasis>.
				Além disso o <emphasis>demoiselle-core</emphasis> disponibiliza o tipo especial de mensagem <emphasis>AttributeChangeMessage</emphasis>, que permite
				especificar além do texto da mensagem enviada, dados sobre a mudança de valor de um atributo, como o nome do atributo alterado, o valor antigo e o novo.
			</para>
			<para>
				Notificações contendo mensagens do tipo <emphasis>AttributeChangeMessage</emphasis> são automaticamente enviadas por padrão pelo framework quando um
				agente de monitoração altera o valor de uma propriedade anotada com <emphasis>@ManagedProperty</emphasis>, mas você também pode enviar mensagens desse tipo
				quando propriedades de sua aplicação são alteradas. Extensões e componentes compatíveis com a API de monitoração do <emphasis>Demoiselle Framework</emphasis>
				(por exemplo, a extensão <emphasis>demoiselle-jmx</emphasis>) podem fornecer implementações específicas da interface <emphasis>Notification</emphasis> e
				tipos especializados de mensagem. Consulte a documentação desses componentes para aprender sobre seus usos. 
			</para>
		</section>
		
	</section>
	
	<section>
		<title>Conectando um cliente de monitoração</title>
		
		<para>O <emphasis>demoiselle-core</emphasis> contém as funcionalidades necessárias para marcar aspectos monitoráveis de sua aplicação,
		mas não conta com nenhum mecanismo para estabelecer uma conexão com um cliente de monitoração. Para isso utiliza-se extensões do framework.</para>
		
		<para>A extensão padrão do framework <emphasis>Demoiselle</emphasis> responsável pela tecnologia de monitoração é a <emphasis>demoiselle-jmx</emphasis>.
		Essa extensão utiliza a especificação JMX (JSR 3) e permite registrar as classes marcadas para monitoração como <emphasis>MBeans</emphasis>.
		Uma vez que as classes sejam registradas como <emphasis>MBeans</emphasis>, seus atributos e operações expostos para monitoração podem ser
		acessados via JMX por um cliente adequado, como o <emphasis>JConsole</emphasis> que acompanha por padrão o JDK da Oracle.</para>
		
		<tip>
			<para>Para acrescentar a extensão <emphasis>demoiselle-jmx</emphasis> em um projeto Maven, adicione a dependência abaixo no arquivo <emphasis>pom.xml</emphasis>.</para>
			
			<programlisting role="XML"><![CDATA[
<dependency>
  <groupId>br.gov.frameworkdemoiselle</groupId>
  <artifactId>demoiselle-jmx</artifactId>
  <scope>compile</scope>
</dependency>]]></programlisting>
		</tip>
		
		<tip>
			<para>A API de monitoração é compatível com o uso de múltiplas extensões simultãneas. Adicione em seu projeto a dependência às extensões desejadas e configure-as
			individualmente, as classes monitoradas serão então expostas para todas as extensões escolhidas.</para>
		</tip>
		
		<para>A figura <xref linkend="exemplo_jconsole" /> mostra como uma classe monitorada é exibida no <emphasis>JConsole</emphasis>.</para>
		
		<programlisting role="JAVA"><![CDATA[@ManagementController
public class HelloWorldManager {
	
	@Inject
	private HelloWorld helloWorld;

	@ManagedOperation(type=OperationType.ACTION)
	public void saySomething(String whatToSay){
		helloWorld.say(whatToSay);
	}

}]]></programlisting>
		
		<figure id="exemplo_jconsole"><title>JConsole acessando uma aplicação monitorada</title>
			<mediaobject>
				<imageobject>
					<imagedata fileref="images/jmx-jconsole-example.png" width="90%" />
				</imageobject>
				<textobject><phrase>JConsole acessando a aplicação <emphasis>Bookmark</emphasis></phrase></textobject>
			</mediaobject>
		</figure>
		
		<para>
			É possível perceber os seguintes elementos nessa imagem:
			<itemizedlist>
				<listitem>Uma classe gerenciada <emphasis>HelloWorldManager</emphasis> com uma operação chamada <emphasis>saySomething</emphasis></listitem>
				<listitem>Uma classe geradora de notificações <emphasis>NotificationBroadcaster</emphasis> responsável por converter as notificações para a API JMX</listitem>
			</itemizedlist>
		</para>
		
		<para>
			Através do <emphasis>JConsole</emphasis> é possível invocar comandos e acessar atributos em todas as classes anotadas com <emphasis>@ManagementController</emphasis>
			em aplicações que usam o <emphasis>demoiselle-jmx</emphasis>. Também é possível inscrever-se às notificações enviadas por <emphasis>NotificationBroadcaster</emphasis>
			e receber todas as notificações enviadas pela aplicação.
		</para>
		
	</section>
		

</chapter>