Avançar para a área de conteúdo

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

Na primeira vez que você efetua sign in no developerWorks, um perfil é criado para você. Informações selecionadas do seu perfil developerWorks são exibidas ao público, mas você pode editá-las a qualquer momento. Seu primeiro nome, sobrenome (a menos que escolha ocultá-los), e seu nome de exibição acompanharão o conteúdo que postar.

Todas as informações enviadas são seguras.

  • Fechar [x]

Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

Todas as informações enviadas são seguras.

  • Fechar [x]

Utilizando Amazon Web Services para Integração de Aplicativos Corporativos

Sistema de mensagens XML com Amazon SQS

Brian J Stewart, Principal Consultant, Aqua Data Technologies, Inc.
Photo of Brian Stewart
Brian J. Stewart é atualmente o consultor principal da Aqua Data Technologies, uma empresa fundada com foco em gerenciamento de conteúdo, tecnologias XML e sistemas Web e cliente-servidor corporativos. Ele arquiteta e desenvolve soluções corporativas com base nas plataformas Java EE e Microsoft .NET. Brian mantém um blog em BrianJStewart.com.

Resumo:  Descubra como utilizar XML e Amazon Web Services para integrar aplicativos corporativos e criar recursos de integração de aplicativos entre plataformas usando as plataformas Microsoft® .NET (C#) e Java™ .

Data:  21/Mar/2011
Nível:  Intermediário Também disponível em :   Inglês
Atividade:  1139 visualizações
Comentários:  


A queue é uma estrutura de dados usada para armazenar mensagens aguardando processamento. Amazon Simple Queue Services (Amazon SQS) é uma fila de mensagens altamente disponível e escalável habilitada para serviços da Web. Os benefícios principais da Amazon SQS são:

Acrônimos usados frequentemente

  • API: Interface de programação de aplicativos
  • DOM: Modelo de objeto de documento
  • HTTP: Protocolo de transporte de Hipertexto
  • XML: Linguagem de marcação extensível
  • Solução baseada na nuvem. Gerenciado por Amazon, nenhum conhecimento de infraestrutura nas instalações ou de suporte é necessário.
  • Baseado na Internet. O serviço pode ser acessado por meio de serviços da Web em qualquer cliente com acesso à Internet, dessa forma permitindo a integração business-to-business (B2B).
  • Redundância. O serviço armazena todas as mensagens em vários servidores para fornecer alta disponibilidade e tolerância a falhas.
  • Várias leituras/gravações simultâneas. Amazon SQS suporta vários processos de leitura e gravação em uma fila simultaneamente e bloqueia mensagens durante a janela de processamento para impedir que dois clientes processem uma mensagem simultaneamente.
  • Configurável. Com o serviço Amazon SQS, é possível projetar a janela de bloqueio com base nos requisitos de processamento exclusivos das mensagens armazenadas na fila. A janela de bloqueio impede que dois leitores da fila processem o mesmo item da fila. Uma janela maior é necessária para itens da fila que levam mais tempo para serem processados. A janela de bloqueio é controlada pelo parâmetro de tempo limite de visibilidade, que é possível configurar fila por fila.
  • API simples de usar. Fornece wrappers de API para linguagens comuns, incluindo as plataformas Java e Microsoft .NET, para permitir o rápido desenvolvimento e a integração perfeita aos aplicativos existentes.
  • Solução de baixo custo. As empresas pagam apenas pela largura de banda que usam e pelas solicitações de HTTP; Amazon SQS não tem nenhuma estrutura de taxa mínima.

É útil conhecer algumas características do Amazon SQS antes de entrar no desenvolvimento do Amazon SQS. Sem conhecimento dessas características, é possível que você considere o trabalho com o Amazon SQS frustrante e confuso inicialmente.

Primeiro, Amazon não dá nenhuma garantia da ordem em que os itens da fila são processados. Isso significa que o processamento primeiro a entrar, primeiro a sair (FIFO) não é garantido, como é comum com muitas implementações de fila de mensagens. Amazon garante apenas que todas as mensagens serão entregues.

A segunda característica importante do Amazon SQS é o conceito de consistência eventual. Os recursos principais de sistemas de banco de dados grandes são consistência, alta disponibilidade e escalabilidade. Em vez de volta o foco para os três, Amazon optou por enfocar a alta disponibilidade e a escalabilidade e fornecer consistência eventual. Isso significa que o Amazon propaga todas as mensagens a vários servidores para alcançar alta disponibilidade e escalabilidade. Amazon garante que todas as mensagens serão entregues, mas não dá nenhuma garantia de quando elas serão entregues. A partir de uma perspectiva prática, isso significa que se você enviar três mensagens para uma fila, na próxima tentativa de receber as mensagens, não haverá nenhuma garantia de que as três mensagens serão recebidas. É possível receber as três mensagens em uma única Leitura ou duas mensagens na primeira Leitura e a terceira mensagem em uma Leitura subsequente . Se você pesquisar a fila continuamente, receberá as três mensagens consequentemente.

Para começar a trabalhar com o Amazon SQS, é preciso obter a biblioteca de API do Amazon SQS com base na linguagem sendo usada. Amazon fornece uma biblioteca para todas as linguagens comuns, como Perl, Microsoft Visual Basic®.NET, C#, Java e PHP. As bibliotecas são software livre e simples de usar. Consulte Recursos para os links para fazer o download dessas bibliotecas.

Usando Amazon SQS com a linguagem Java

Inicialmente, você verá como criar uma fila, enviar uma mensagem e receber uma mensagem usando a linguagem Java. A primeira etapa é criar uma fila Amazon SQS. O código na Listagem 1 mostra como criar o cliente HTTP para o Amazon SQS, instanciar o objeto CreateQueueRequest e chamar a solicitação de criação de fila. O ID de chave de acesso é a chave (20 caracteres, sequência alfanumérica) necessária para solicitar autenticação ou ler itens da fila de mensagens. Para criar ou manipular itens de fila, é preciso ter a chave de acesso secreta (40 caracteres, sequência alfanumérica). Você recebe essas chaves ao se registrar no Amazon. (Consulte Recursos para obter um link para um artigo sobre segurança na nuvem que descreve essas chaves em mais detalhes.)


Listagem 1. Criar a fila Amazon SQS
	
String queueName = "TestQueue";

// create http client
AmazonSQS service = new AmazonSQSClient(accessKeyId, secretAccessKey);

// instantiate create queue request
CreateQueueRequest request = new CreateQueueRequest();
request.setQueueName(queueName);
request.setDefaultVisibilityTimeout(30);

// execute create queue operation and get the server response
System.out.print("Creating Queue: " + queueName);    
CreateQueueResponse response = service.createQueue(request);
if (response.isSetCreateQueueResult()) {
	System.out.print("Create Queue Result:");    
	CreateQueueResult createQueueResult = response.getCreateQueueResult();
	if (createQueueResult.isSetQueueUrl()) {
		System.out.print("Queue Url: " + createQueueResult.getQueueUrl());
	}
}

A próxima etapa é enviar uma mensagem à fila recém-criada. O código na Listagem 2 mostra como criar o cliente HTTP para Amazon SQS e como enviar uma mensagem simples à fila.


Listagem 2. Enviar uma mensagem à fila
	
String queueName = "TestQueue";

// create http client
AmazonSQS service = new AmazonSQSClient(accessKeyId, secretAccessKey);

// instantiate send message request
SendMessageRequest request = new SendMessageRequest();
request.setQueueName(queueName);
request.setMessageBody("Test SQS Message");

// execute the send message operation and get the server response
SendMessageResponse response = service.sendMessage(request);
if (response.isSetSendMessageResult()) {
	System.out.print("Send Message Result: ");

	SendMessageResult sendMessageResult = response.getSendMessageResult();
	if (sendMessageResult.isSetMessageId()) {
		System.out.print("\tMessageId: " + sendMessageResult.getMessageId());
	}
} 

Agora, receba a mensagem da fila. A Listagem 3 mostra como criar o cliente HTTP para Amazon SQS e como receber uma mensagem da fila. Message contém a mensagem da fila e expõe vários métodos principais:

  • getMessageId. Retorna o identificador exclusivo da mensagem. É possível usar isSetMessageId para determinar se o ID da mensagem foi definido.
  • getReceiptHandle. Retorna o identificador para a mensagem. O identificador é usado para excluir a mensagem. É possível usar isSetReceiptHandle para determinar se o identificador da mensagem foi definido.
  • getBody. Retorna o corpo da mensagem em uma cadeia de caractere. A mensagem pode ser texto simples ou XML, e é possível usar isSetBody para determinar se o corpo da mensagem foi definido.

Listagem 3. Receber uma mensagem da fila
	
String queueName = "TestQueue";

// create http client
AmazonSQS service = new AmazonSQSClient(accessKeyId, secretAccessKey);

// instantiate the receive message request
ReceiveMessageRequest request = new ReceiveMessageRequest();
request.setQueueName(queueName);
// the following two parameters are optional
request.setMaxNumberOfMessages(10); // set maximum number of messages to receive
request.setVisibilityTimeout(30); // set visibility window
		 
// execute the receive messages operation and get server response
ReceiveMessageResponse response = service.receiveMessage(request);

System.out.print("Receive Message Response:");

if (response.isSetReceiveMessageResult()) {
	ReceiveMessageResult  receiveMessageResult = response.getReceiveMessageResult();
	java.util.List<Message> messageList = receiveMessageResult.getMessage();
	for (Message message : messageList) {			
		if (message.isSetMessageId()) {
			System.out.print("MessageId: " + message.getMessageId());
		}

		if (message.isSetReceiptHandle()) {
			System.out.print("ReceiptHandle: " + message.getReceiptHandle());
		}
		if (message.isSetBody()) {
			System.out.print("Body: " + message.getBody());
		}
}

Usando Amazon SQS com C#

Agora, você serializará um objeto para XML e o enviará como uma mensagem Amazon SQS usando C#.

A primeira etapa é criar um objeto de negócios que será serializado; a Listagem 4 mostra um objeto Product. As propriedades públicas são decoradas com os atributos para controlar a serialização XML. Os atributos C#, que são similares às anotações Java, definem como as propriedades são mapeadas para elementos XML ou atributos XML. Além disso, a classe contém o método ToXml() , que serializa a instância do objeto para XML.


Listagem 4. Criar um objeto de negócios para serialização
	
namespace Stewart.Test
{
/// <summary>
/// Product
/// </summary>
[XmlRoot(ElementName="Product")]
public class Product
{
	/// <summary>
	/// Product Name
	/// </summary>
	[XmlElement("ProductName")]
	public string ProductName;

	/// <summary>
	/// Product Price
	/// </summary>
	[XmlElement("ProductPrice")]
	public decimal ProductPrice;

	/// <summary>
	/// Quantity in stock
	/// </summary>
	[XmlElement("InStock")]
	public bool InStock;

	/// <summary>
	/// Product Id
	/// </summary>
	[XmlAttributeAttribute(AttributeName = "Id", DataType = "integer")]
	public string Id;

	/// <summary>
	/// Initializes a new instance of the <see cref="Product"/> class.
	/// </summary>
	public Product()
	{
	}

	/// <summary>
	/// Initializes a new instance of the <see cref="Product"/> class.
	/// </summary>
	/// <param name="productName">Name of the product.</param>
	/// <param name="productPrice">The product price.</param>
	public Product(string productName, decimal productPrice)
	{
		this.ProductName = productName;
		this.ProductPrice = productPrice;
	}

	/// <summary>
	/// Converts to XML.
	/// </summary>
	/// <returns></returns>
	public String ToXml()
	{
		StringBuilder output = new StringBuilder();

		// no name space
		XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
		ns.Add("", "");

		// settings to omit xml declaration
		XmlWriterSettings settings = new XmlWriterSettings();
		settings.OmitXmlDeclaration = true;

		// finally serialize to string
		XmlWriter writer = XmlTextWriter.Create(output, settings);
		XmlSerializer serializer = new XmlSerializer(typeof(Product));            
		serializer.Serialize(writer, this, ns);

		// return string containing XML document
		return output.ToString();
	}
}

Em seguida, envie a mensagem XML. A API Amazon C# para Amazon SQS é funcionalmente equivalente e similar a Java API. O código na Listagem 5 mostra como enviar a mensagem usando C#.


Listagem 5. Enviar a mensagem usando C#
	
Product prod = new Product("Widget", 1.5M);
string accessKeyId = ConfigurationSettings.AppSettings["AmazonAccessKeyID"];
string secretAccessKey = ConfigurationSettings.AppSettings["AmazonSecretAccessKey"];

AmazonSQS service = new AmazonSQSClient(accessKeyId, secretAccessKey);
SendMessageRequest request = new SendMessageRequest();
request.MessageBody = prod.ToXml();
request.QueueName = "TestQueue";

SendMessageResponse response = service.SendMessage(request);
if (response.IsSetSendMessageResult())
{
	Console.WriteLine("Send Message Response: ");
	SendMessageResult sendMessageResult = response.SendMessageResult;
	if (sendMessageResult.IsSetMessageId())
	{
		Console.WriteLine(String.Format("MessageId {0}", 
			sendMessageResult.MessageId));
	}
	if (sendMessageResult.IsSetMD5OfMessageBody())
	{
		Console.WriteLine(String.Format("MD5OfMessageBody: {0}", 
			sendMessageResult.MD5OfMessageBody));
	}
} 

Figura 1 mostra a saída da Listagem 5.


Figura 1. Enviar saída da mensagem XML

A etapa final é receber a mensagem XML da fila e desserializar a instância. A Listagem 6 mostra o código para desserializar a mensagem XML em uma instância de Product .


Listagem 6. Desserializar a mensagem XML
	
Product prod = null;            

string accessKeyId = ConfigurationSettings.AppSettings["AmazonAccessKeyID"];
string secretAccessKey = ConfigurationSettings.AppSettings["AmazonSecretAccessKey"];

AmazonSQS service = new AmazonSQSClient(accessKeyId, secretAccessKey);

ReceiveMessageRequest request = new ReceiveMessageRequest();
request.QueueName = "TestQueue";
ReceiveMessageResponse response = service.ReceiveMessage(request);

if (response.IsSetReceiveMessageResult())
{
	Console.WriteLine("Receive Message Result:");
	ReceiveMessageResult receiveMessageResult = response.ReceiveMessageResult;
	List<Message> messageList = receiveMessageResult.Message;
	foreach (Message message in messageList)
	{                    
		if (message.IsSetMessageId())
		{
			Console.WriteLine(String.Format("MessageId: {0}",
				message.MessageId));
		}                                      
		if (message.IsSetBody())
		{
			Console.WriteLine(string.Format("Body: {0}", message.Body));
			String xml = message.Body;
			StringReader sr = new StringReader(xml);
			XmlSerializer serializer = new XmlSerializer(typeof(Product));
			prod = (Product) serializer.Deserialize(sr);
			Console.WriteLine(string.Format("Id: {0}", prod.Id));
			Console.WriteLine(string.Format("Name: {0}", prod.ProductName));
			Console.WriteLine(string.Format("Price: {0}", prod.ProductPrice));
		}
	}
} 

Figura 2 mostra a saída da Listagem 6.


Figura 2. Receber saída da mensagem XML

Embora a amostra acima seja muito simples, ela é muito poderosa porque é possível serializar um objeto e enviar a mensagem a outro aplicativo cujos limites de aplicativo não possuem restrição para uma rede física local. Não há nenhuma restrição de firewall complexa ou consideração de segurança. Além disso, o remetente e o destinatário da mensagem não precisam ser escritos na mesma linguagem ou até mesmo usar a mesma plataforma.

Visão geral e design técnico

A solução de demonstração consiste em um revendedor e um fabricante que precisam integrar seus processos de negócios. O revendedor compra widgets do fabricante e os vende aos cliente.

Quando um cliente quer widgets, o revendedor usa um cliente C# WinForm para enviar ao cliente uma ordem. O programa de envio de ordens armazena os detalhes da ordem em um banco de dados MySQL local. O cliente também permite que os usuários busquem inventários, visualizem ordens e visualizem as filas de mensagens do Amazon SQS.

Normalmente, o revendedor tem widgets suficientes no inventário para atender à ordem do cliente. Caso contrário, o revendedor envia uma ordem de compra ao fabricante quase em tempo real. O fabricante enviará de volta um resumo das ordens quando os itens tiverem sido enviados. Toda a comunicação é feita com o uso do Amazon SQS.

Os serviços Order Fulfillment e Inventory Management do revendedor, que são também criados com o uso de C#, pesquisa merchandises recebidos e ordens pendentes dos clientes. Se, durante o processamento de uma ordem do cliente, o inventário de widgets estiver menor do que o número pedido, uma nova ordem de compra será enviada ao fabricante que usa o Amazon SQS. O corpo da mensagem do item de fila é um documento XML que contém a ordem de compra.

O serviço Order Processing do fabricante, que é criado na plataforma Java, processa a fila de ordens de compra. Ele enviará uma mensagem de volta ao revendedor usando Amazon SQS quando os itens tiverem sido enviados. O corpo da mensagem é o documento que contém o resumo das ordens.

O diagrama da Figura 3 mostra os sistemas envolvidos.


Figura 3. Visão geral da solução

Criar os esquemas XML

A primeira etapa é definir os esquemas XML das mensagens enviadas entre o revendedor e o fabricante. Dois esquemas são necessários: uma ordem de compra e um resumo das ordens.

Listagem 7 mostra o esquema da ordem de compra.


Listagem 7. Esquema da ordem de compra
	
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="PurchaseOrder">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="Id" type="xs:string" minOccurs="0" />
        <xs:element name="OrderDate" type="xs:string" minOccurs="0" />
        <xs:element name="Company" minOccurs="0" maxOccurs="unbounded">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="CompanyName" type="xs:string" minOccurs="0" />
              <xs:element name="StreetAddress" type="xs:string" minOccurs="0" />
              <xs:element name="City" type="xs:string" minOccurs="0" />
              <xs:element name="State" type="xs:string" minOccurs="0" />
              <xs:element name="ZipCode" type="xs:string" minOccurs="0" />
            </xs:sequence>
          </xs:complexType>
        </xs:element>
        <xs:element name="Vendor" minOccurs="0" maxOccurs="unbounded">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="CompanyName" type="xs:string" minOccurs="0" />
              <xs:element name="StreetAddress" type="xs:string" minOccurs="0" />
              <xs:element name="City" type="xs:string" minOccurs="0" />
              <xs:element name="State" type="xs:string" minOccurs="0" />
              <xs:element name="ZipCode" type="xs:string" minOccurs="0" />
            </xs:sequence>
          </xs:complexType>
        </xs:element>
        <xs:element name="Items" minOccurs="0" maxOccurs="unbounded">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="Item" minOccurs="0" maxOccurs="unbounded">
                <xs:complexType>
                  <xs:attribute name="Id" type="xs:string" />
                  <xs:attribute name="Name" type="xs:string" />
                  <xs:attribute name="Quantity" type="xs:string" />
                </xs:complexType>
              </xs:element>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>  
</xs:schema>		

O esquema XML de ordens de compra consiste nos seguintes elementos principais:


Tabela 1. Elementos principais no esquema de ordem de compra
Elementos principaisDescrição
IdCadeia de caractere que contém o identificador exclusivo da ordem de compra
OrderDateCadeia de caractere que contém a data da ordem de compra
CompanyContém as informações de endereço principais relacionadas ao revendedor, incluindo nome da empresa, endereço, cidade, estado e CEP
VendorContém as informações de endereço principais relacionadas ao fornecedor, incluindo nome da empresa, endereço, cidade, estado e CEP
ItemsContém todos os itens solicitados, incluindo ID do item, nome do item e quantidade

Listagem 8 mostra o esquema do resumo de ordens.


Listagem 8. Esquema do resumo de ordens
	
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="OrderSummary">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="OrderId" type="xs:string" minOccurs="0" />
        <xs:element name="ReferenceId" type="xs:string" minOccurs="0" />
        <xs:element name="OrderDate" type="xs:string" minOccurs="0" />
        <xs:element name="CompanyAddress" minOccurs="0" maxOccurs="unbounded">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="CompanyName" type="xs:string" minOccurs="0" />
              <xs:element name="StreetAddress" type="xs:string" minOccurs="0" />
              <xs:element name="City" type="xs:string" minOccurs="0" />
              <xs:element name="State" type="xs:string" minOccurs="0" />
              <xs:element name="ZipCode" type="xs:string" minOccurs="0" />
            </xs:sequence>
          </xs:complexType>
        </xs:element>
        <xs:element name="CustomerAddress" minOccurs="0" maxOccurs="unbounded">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="CompanyName" type="xs:string" minOccurs="0" />
              <xs:element name="StreetAddress" type="xs:string" minOccurs="0" />
              <xs:element name="City" type="xs:string" minOccurs="0" />
              <xs:element name="State" type="xs:string" minOccurs="0" />
              <xs:element name="ZipCode" type="xs:string" minOccurs="0" />
            </xs:sequence>
          </xs:complexType>
        </xs:element>
        <xs:element name="Items" minOccurs="0" maxOccurs="unbounded">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="Item" minOccurs="0" maxOccurs="unbounded">
                <xs:complexType>
                  <xs:attribute name="ItemId" type="xs:string" />
                  <xs:attribute name="ItemName" type="xs:string" />
                  <xs:attribute name="Quantity" type="xs:string" />
                </xs:complexType>
              </xs:element>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>  
</xs:schema>

O esquema XML de resumo de ordens consiste nos seguintes componentes principais:


Tabela 2. Elementos principais no esquema de resumo de ordens de compra.
IdCadeia de caractere que contém o identificador exclusivo do resumo de ordens
ReferenceIdCadeia de caractere que contém o ID da ordem de compra original
OrderDateCadeia de caractere que contém a data do resumo de ordens de compra
CustomerAddressContém as informações de endereço principais relacionadas ao revendedor, incluindo nome da empresa, endereço, cidade, estado e CEP
VendorAddressContém as informações de endereço principais relacionadas ao fornecedor, incluindo nome da empresa, endereço, cidade, estado e CEP
ItemsContém todos os itens solicitados, incluindo ID do item, nome do item e quantidade

Definir o modelo de entidade de banco de dados

Em seguida, defina o esquema do banco de dados. Figura 4 mostra o diagrama do modelo de entidade de banco de dados.


Figura 4. Modelo de entidade de banco de dados

As entidades de dados do revendedor incluem o seguinte:

  • Customer contém as informações de contato do cliente para pedidos.
  • CustomerOrder contém as informações da ordem para a ordem do cliente.
  • CustomerOrderDetail contém detalhes de item de ordem para a ordem do cliente.
  • Inventory contém o inventário para o revendedor.

A entidade de dados do fabricante é:

  • VendorOrder controla as ordens de compra processadas pelo serviço Order Processing do fabricante.

Definir as filas de mensagens

Os últimos componentes que precisam ser definidos são as filas de mensagens. Tabela 3 mostra as filas de mensagens dessa solução.


Tabela 3. Filas de mensagens de Amazon SMS
Nome da filaTempo limite de visibilidadeFinalidade
POQueue30 segundosMensagens de ordem de compra enviadas do revendedor para o fabricante
OSQueue30 segundosMensagens de resumo de ordens enviadas do fabricante ao revendedor

A implementação do revendedor

O aplicativo do revendedor consiste nas seguintes entidades na Tabela 4.


Tabela 4. Entidades de negócios no aplicativo do revendedor
ClasseDescrição
CompanyAddressEntityContém um cliente ou um endereço comercial
CustomerEntityContém um cliente
OrderEntityContém um pedido do cliente
OrderDetailEntityContém o detalhe em nível de itens de uma ordem do cliente
InventoryItemEntityContém um item de inventário
PurchaseOrderEntityContém uma ordem de compra
PurchaseOrderDetailEntityContém o detalhe em nível de itens de uma ordem de compra

No lado do Microsoft .NET, a classe BaseSQSDataProvider também fornece uma classe de utilitário para sistema de mensagens de Amazon SQS. O BaseDbProvider fornece uma classe de utilitário para trabalhar com bancos de dados MySQL.


O sistema de gerenciamento de ordens do revendedor

O cliente de gerenciamento de ordens do revendedor não é o foco deste artigo, mas o cliente é bem direto. É escrito em C# e é um aplicativo de n camadas com todos os negócios e dados separados da camada de apresentação. Toda a ligação do formulário é feita com o uso dos recursos poderosos de ligação de objeto do Microsoft .NET. Todas as listas suspensas, visualizações em grade e campos de formulário estão vinculados aos objetos de negócios. O código que está por trás dos formulários Windows® é mínimo, visto que a lógica de negócios reside na camada de lógica de negócios.

Figura 5 mostra o cliente.


Figura 5. Cliente de gerenciamento de ordens do revendedor


O serviço de preenchimento de ordens do revendedor

A classe OrderFulfillmentService é responsável por processar ordens do cliente e faz isso com base no intervalo de pesquisa especificado no arquivo App.config. O serviço recupera uma lista de ordens ainda não processadas. Para cada ordem na lista, as seguintes ações ocorrem nos métodos correspondentes:

  • Verifique se a ordem pode ser enviada—ou seja, existe inventário suficiente (método ProcessPendingOrders ).
  • Processe a ordem se ela puder ser enviada (método CanShip ).
  • Coloque a ordem em pedido em atraso se ela não puder ser enviada e envie a ordem de compra ao fabricante (método ProcessBackorder ).

Listagem 9 mostra o método ProcessPendingOrders() .


Listagem 9. O método ProcessPendingOrders()
	
	public int ProcessPendingOrders()
	{
		int itemsProcessed = 0;

		// get orders not yet shipped
		CustomerOrderFactory factory = new CustomerOrderFactory();
		IList<OrderEntity> orders = factory.GetOrdersNotYetShipped();

		// iterate through all orders not processed
		IEnumerator<OrderEntity> ordersEnum = orders.GetEnumerator();
		while (ordersEnum.MoveNext()) {
			// get next order
			OrderEntity curOrder = ordersEnum.Current;
			Console.WriteLine(string.Format("Processing Order '{0}'...", 
				curOrder.Id));

			// check if merchandise is available to ship
			if (this.CanShip(curOrder)) {
				// process order
				if (this.ProcessOrder(curOrder)) {
					itemsProcessed++;
				}
			}// if can ship order
			else if (!curOrder.IsBackordered){
				// set order to backordered
				if (this.ProcessBackorder(curOrder)) {
					itemsProcessed++;
				}
			} // if can't ship order (not enough merchandise)
		} // while more orders to process

		return itemsProcessed;
	}

Para determinar se a ordem pode ser processada, a quantidade do item solicitada será verificada em relação ao nível de inventário de cada item. Listagem 10 mostra o método CanShip() .


Listagem 10. O método CanShip()
	
private bool CanShip(OrderEntity order)
{
bool hasMerchandise = true;            

// get items
IEnumerator<OrderDetailEntity> detailEnum = order.GetOrderItems();

// iterate through all items
while (detailEnum.MoveNext())
{
	// get current item
	OrderDetailEntity detailEntry = detailEnum.Current;

	InventoryItemEntity inventoryItem = detailEntry.Item;
	if (detailEntry.Quantity > inventoryItem.Quantity)
	{
		Console.WriteLine(
			string.Format("Order {0} - Insufficient Inventory: {1} ({2})",
			order.Id, inventoryItem.Name, inventoryItem.Id));
		hasMerchandise = false;
	} // if inventory is sufficient
} // while more entries to process

Console.WriteLine(string.Format("Order {0} - Can Ship: {1}", 
	order.Id, hasMerchandise));
return hasMerchandise;
}    			

Se o CanShip() retornar False e a ordem não tiver ainda sido definida como pedido em atraso, o método ProcessBackorder() será chamado, e a propriedade IsBackordered da ordem será definida como True. Use MessageQueueFactory para criar o item de fila e enviar a mensagem de ordem de compra. Listagem 11 mostra esse processo.


Listagem 11. O método ProcessBackorder()
	
private bool ProcessBackorder(OrderEntity order)
{
	// set to backordered
	order.IsBackordered = true;       

	// update order
	CustomerOrderFactory factory = new CustomerOrderFactory();
	bool result = factory.UpdateOrder(order);

	if (!result) return result;

	// get purchase order xml
	string poXml = this.GetPurchaseOrderAsXml(order);            

	// create message queue
	MessageQueueFactory queueFactory = new MessageQueueFactory();
	return queueFactory.CreatePOQueueItem(poXml);
}

O objeto PurchaseOrderEntity é criado através do método GetPurchaseOrder() . Um OrderDetailEntity é adicionado à ordem para cada item com níveis de inventário insuficientes. Listagem 12 mostra esse processo.


Listagem 12. O método GetPurchaseOrder()
	
private PurchaseOrderEntity GetPurchaseOrder(OrderEntity order)
{
PurchaseOrderEntity po = new PurchaseOrderEntity();

po.PurchaseDate = DateTime.Now;

// set company address of the Purchase Order - the Reseller
po.CompanyAddress.CompanyName = "The Widget Factory";
po.CompanyAddress.StreetAddress = "100 Main Street";
po.CompanyAddress.CityName = "Las Vegas";
po.CompanyAddress.StateName = "NV";
po.CompanyAddress.ZipCode = "89044";

// set vendor address of the Purchase Order - the Manufacturer
po.VendorAddress.CompanyName = "Widget Supplies";
po.VendorAddress.StreetAddress = "100 Main Street";
po.VendorAddress.CityName = "Orlando";
po.VendorAddress.StateName = "FL";
po.VendorAddress.ZipCode = "32801";

// while more items to process
IEnumerator<OrderDetailEntity> orderEnum = order.GetOrderItems();
while (orderEnum.MoveNext())
{
	OrderDetailEntity orderItem = orderEnum.Current;
	InventoryItemEntity inventoryItem = orderItem.Item;

	// if insufficient inventory
	if (orderItem.Quantity > inventoryItem.Quantity)
	{
		// order the number needed plus 100
		int quantityToOrder = (orderItem.Quantity - inventoryItem.Quantity) + 100;
		PurchaseOrderDetailEntity poItem = new PurchaseOrderDetailEntity();
		poItem.ItemName = inventoryItem.Name;
		poItem.ItemId = inventoryItem.Id;
		poItem.Quantity = quantityToOrder;

		// add item to po
		po.AddItem(poItem);
	}
}

return po;            
}

A próxima etapa é serializar PurchaseOrderEntity para XML. O Microsoft .NET Framework oferece recursos de serialização de XML poderosos. Crie uma instância de XmlSerializerNamespaces para definir o namespace XML do documento de saída. Crie uma instância de XmlWriterSettings para controlar a saída de XML. Sua intenção é omitir a declaração de XML da saída porque ela está sendo integrada ao corpo da mensagem. Use a classe XmlTextWriter para serializar o objeto para um editor de texto XML que escreve sua saída em uma instância de StringBuilder. Finalmente, use o método Serialize() deXmlSerializer para serializar a instância dePurchaseOrderEntity para XML. Listagem 13 mostra esse processo.


Listagem 13. O método GetPurchaseOrderAsXml()
	
private string GetPurchaseOrderAsXml(OrderEntity order)
{
// get purchase order
PurchaseOrderEntity po = this.GetPurchaseOrder(order); ;

StringBuilder output = new StringBuilder();

// no name space
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");

// settings to omit 
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;

XmlWriter writer = XmlTextWriter.Create(output, settings);
XmlSerializer serializer = new XmlSerializer(typeof(PurchaseOrderEntity));
serializer.Serialize(writer, po, ns);

Debug.WriteLine(output.ToString());

return output.ToString();}

Agora, envie uma mensagem contendo a ordem de compra para a fila Amazon SQS usando o código da Listagem 14.


Listagem 14. O método CreatePOQueueItem()
	
public bool CreatePOQueueItem(String poXml)
{
MessageQueueSQSDataProvider queueFactory = DW4DataContext.MessageQueueData;
MessageQueueEntity message = new MessageQueueEntity();
message.MessageBody = poXml;
message.MessageType = MessageTypes.PurchaseOrder;
return queueFactory.InsertQueueItem(message);			
}

O método InsertQueueItem() de MessageQueueSQSDataProvider cria o item de fila na fila correta com base no tipo de mensagem. O método chama o método base SendMessage() para enviar a mensagem à fila Amazon SQS, como na Listagem 15.


Listagem 15. O método InsertQueueItem()
	
public bool InsertQueueItem(MessageQueueEntity message)
{
String queueName = null;
if (message.MessageType == MessageTypes.OrderSummary)
{
	queueName = ConfigurationSettings.AppSettings["OrderSummaryQueue"];
	return this.SendMessage(queueName, message.MessageBody);
}
else if (message.MessageType == MessageTypes.PurchaseOrder)
{
	queueName = ConfigurationSettings.AppSettings["PurchaseOrderQueue"];
	return this.SendMessage(queueName, message.MessageBody);
}

return false;            
}

O método SendMessage() cria SendMessageRequest, que faz parte da API Amazon. Os parâmetros obrigatórios são o nome da fila e o corpo da mensagem (um documento XML). Se SendMessageResponse não for nulo, isso indica que a mensagem foi enviada com êxito. As próximas linhas mostram de maneira simples as informações de depuração principais para solucionar problemas. O método SendMessage() completo está na Listagem 16.


Listagem 16. O método SendMessage()
	
public bool SendMessage(string queueName, string messageBody) {
bool result = true;
try {
	String accessKeyId = 
		ConfigurationSettings.AppSettings["AmazonAccessKeyID"]; ;
	String secretAccessKey = 
		ConfigurationSettings.AppSettings["AmazonSecretAccessKey"];
	AmazonSQS service = new AmazonSQSClient(accessKeyId, secretAccessKey);

	// build request
	SendMessageRequest request = new SendMessageRequest();
	request.QueueName = queueName;
	request.MessageBody = messageBody;
	// send message
	SendMessageResponse response = service.SendMessage(request);
	if (response.IsSetSendMessageResult()) {
		Debug.WriteLine("Send Message Result:");
		SendMessageResult sendMessageResult = response.SendMessageResult;
		if (sendMessageResult.IsSetMessageId()) {
			Debug.WriteLine(String.Format("\tMessageId: {0}", 
				sendMessageResult.MessageId));
		}
		if (sendMessageResult.IsSetMD5OfMessageBody()) {
			Debug.WriteLine("\tMD5 Of Message Body: ", 
				sendMessageResult.MD5OfMessageBody);
		}
	}
	if (response.IsSetResponseMetadata()) {
		Debug.WriteLine("Response Metadata:");
		ResponseMetadata responseMetadata = response.ResponseMetadata;
		if (responseMetadata.IsSetRequestId()) {
			Debug.WriteLine(String.Format("\tRequest Id: {0}", 
				responseMetadata.RequestId));
		}
	}
}
catch (AmazonSQSException ex) {
	Debug.WriteLine("Caught Exception: " + ex.Message);
	Debug.WriteLine("Response Status Code: " + ex.StatusCode);
	Debug.WriteLine("Error Code: " + ex.ErrorCode);
	Debug.WriteLine("Error Type: " + ex.ErrorType);
	Debug.WriteLine("Request ID: " + ex.RequestId);
	Debug.WriteLine("XML: " + ex.XML);
	result = false;
}
return result;
}


O serviço de gerenciamento de inventário do revendedor

InventoryManagementService é responsável por gerenciar o inventário e processar resumos de ordens recebidas do fabricante. Igual a OrderFulfillmentService, o serviço usa o intervalo de pesquisa especificado no arquivo App.config. As seguintes ações ocorrem:

  • O método ProcessIncomingMerchandise() primeiro recebe uma lista de todos os resumos de ordens (OrderSummaryEntity) recebidos, mas ainda não processados.
  • O método InventoryManagementService recupera as mensagens do método Amazon SQS OSQueue.
  • O método ProcessOrderReceipt() é chamado para cada envio não processado.

Listagem 17 mostra como o método ProcessIncomingMerchandise() recupera uma lista.


Listagem 17. O método ProcessIncomingMerchandise()
	
public int ProcessIncomingMerchandise()
{
int itemsProcessed = 0;

OrderSummaryFactory osFactory = new OrderSummaryFactory();
IList<OrderSummaryEntity> orders = osFactory.GetOrderSummariesToProcess();

// iterate through all order summaries
IEnumerator<OrderSummaryEntity> orderEnum = orders.GetEnumerator();
while (orderEnum.MoveNext())
{
	// get current order summary
	OrderSummaryEntity order = orderEnum.Current;

	// process order summary received
	if (this.ProcessOrderReceipt(order))
	{
		itemsProcessed++;
	}
}

Debug.WriteLine(String.Format("Orders Processed: {0}", itemsProcessed));
return itemsProcessed;
}		

O método ProcessOrderReceipt() itera através de cada item (OrderSummaryDetailEntity) no resumo de ordens e aumenta a quantidade de inventário de cada item recebido. Listagem 18 mostra esse método.


Listagem 18. O método ProcessOrderReceipt()
	
private bool ProcessOrderReceipt(OrderSummaryEntity order)
{
	if (order == null) return false;

	bool result = true;

	// add to inventory
	InventoryFactory inventoryFactory = new InventoryFactory();
	
	// iterate through all items in order summary
	IEnumerator<OrderSummaryDetailEntity> itemsEnum = order.Items.GetEnumerator();
	while (itemsEnum.MoveNext())
	{
		// get current item
		OrderSummaryDetailEntity orderItem = itemsEnum.Current;
		
		// get item
		int itemId = orderItem.ItemId;
		InventoryItemEntity item = inventoryFactory.GetInventoryItem(itemId);

		// increase inventory
		item.Quantity = item.Quantity + orderItem.Quantity;
		result = inventoryFactory.UpdateInventoryItem(item);
		if (!result) break;
	}

	if (result)
	{
		MessageQueueFactory queueFactory = new MessageQueueFactory();
		queueFactory.DeleteQueueItem(order.QueueItem);
	}

	return result;
}

A última etapa é excluir o item da fila do resumo de ordens da fila de mensagens se o envio de inventário tiver sido processado com êxito. Listagem 19 mostra como excluir uma mensagem de uma fila do Amazon SQS usando C#.


Listagem 19. O método DeleteMessage()
	
public bool DeleteMessage(string queueName, string messageHandle) {
bool result = false;
try {
  String accessKeyId = 
           ConfigurationSettings.AppSettings["AmazonAccessKeyID"];
  String secretAccessKey = 
           ConfigurationSettings.AppSettings["AmazonSecretAccessKey"];
  AmazonSQS service = new AmazonSQSClient(accessKeyId, secretAccessKey);
 
  // Create delete message request object
  DeleteMessageRequest request = new DeleteMessageRequest();
  
  // Set queue name containing item to be deleted
  request.QueueName = queueName;
  
  // Set handle of message to be deleted
  request.ReceiptHandle = messageHandle;
  
  // Delete message
  DeleteMessageResponse response = service.DeleteMessage(request);
  Debug.WriteLine("Service Response");                
 
  Debug.WriteLine("\tDelete Message Response");
  // If message response
  if (response.IsSetResponseMetadata())
  {
           Debug.WriteLine("\tResponse Metadata");
           ResponseMetadata responseMetadata = response.ResponseMetadata;
           if (responseMetadata.IsSetRequestId())
           {
                   Debug.WriteLine(String.Format("\tRequest Id: {0}", 
                            responseMetadata.RequestId));
           }
  }
}
catch (AmazonSQSException ex)
{
  Debug.WriteLine("Caught Exception: " + ex.Message);
  Debug.WriteLine("Response Status Code: " + ex.StatusCode);
  Debug.WriteLine("Error Code: " + ex.ErrorCode);
  Debug.WriteLine("Error Type: " + ex.ErrorType);
  Debug.WriteLine("Request ID: " + ex.RequestId);
  Debug.WriteLine("XML: " + ex.XML);
}
 
return result;
}


A implementação de fabricante

O último componente da solução é o serviço Order Processing do fabricante, que é o serviço baseado em Java que processa ordens do revendedor. O serviço Order Processing:

  • Pesquisa a fila de ordens de compra, que contém ordens de compra enviadas pelo revendedor.
  • Ao receber uma ordem de compra, ele cria um resumo de ordens e o envia ao revendedor usando uma fila do Amazon SQS diferente.
  • Exclui a ordem de compra recebida pelo revendedor.

O aplicativo do fabricante consiste nas seguintes entidades de negócios na Tabela 5.


Tabela 5. Entidades de negócios no aplicativo do revendedor
ClasseDescrição
AddresssEntityContém um cliente ou um endereço comercial
CustomerOrderEntityContém uma ordem do cliente (ordem de compra)
CustomerOrderDetailEntityContém o detalhe em nível de item para uma ordem do cliente (ordem de compra)
MessageQueueEntityContem um item de fila de mensagens (ou seja, uma ordem de compra ou um resumo de ordens)
OrderSummaryEntityContém um resumo de envios de ordens
OrderSummaryDetailEntityContém o detalhe em nível de itens de um resumo de envios de ordens

Essa solução usa a classe auxiliar JdbcQuery para todas as operações de banco de dados. A solução também usa duas classes auxiliares adicionais: DateUtil para formatação de dados e AppConfig para ler parâmetros de configuração. Além disso, a classe SqsDataProvider é a classe do utilitário que fornece funcionalidade básica do Amazon SQS.


O serviço de processamento de ordens do fabricante

A classe OrderProcessingService é responsável por processar ordens de compra e faz isso com base no intervalo de pesquisa especificado no arquivo AppConfig.properties. O serviço recupera uma lista de ordens de compra não enviadas ainda e as processa. O método getMessageQueueItems, na Listagem 20, mostra como recuperar uma lista de mensagens de uma fila do Amazon SQS especificada com o uso de código Java.


Listagem 20. O método getMessageQueueItems()
	
protected ArrayList<HashMap<String, String>> getMessageQueueItems(String queueName) {
ArrayList<HashMap<String, String>> results = new ArrayList<HashMap<String, String>>();
 
try {
  String accessKeyId = AppConfig.getProperty("AmazonAccessKeyID");
  String secretAccessKey =  AppConfig.getProperty("AmazonSecretAccessKey");
 
  AmazonSQS service = new AmazonSQSClient(accessKeyId, secretAccessKey);
  
  // get messages from queue
  ReceiveMessageRequest request = new ReceiveMessageRequest();
  request.setQueueName(queueName);
  request.setVisibilityTimeout(1);
  
  ReceiveMessageResponse response = service.receiveMessage(request);
  
  // if received response
  if (response.isSetReceiveMessageResult()) {
           System.out.println("\tReceive Message Result");
           ReceiveMessageResult receiveMessageResult = 
                   response.getReceiveMessageResult();
           
           // get all messages and iterate through them
           List<Message> messageList = receiveMessageResult.getMessage();
           for (Message message : messageList) {
                   // build hashmap containing each message
                   HashMap<String, String> row = new HashMap<String, String>();
                   
                   if (message.isSetMessageId()) {
                            row.put(COLUMN_ID, message.getMessageId());
                            System.out.println("\t\tMessageId: " + 
                                     message.getMessageId());
                   }
                   if (message.isSetReceiptHandle()) {
                            row.put(COLUMN_HANDLE, message.getReceiptHandle());
                   }
                   if (message.isSetBody()) {                                   
                            row.put(COLUMN_MESSAGE, message.getBody());
                   }
                   
                   // add row
                   results.add(row);
           }
  }        
} catch (AmazonSQSException ex) {
  System.out.println("Caught Exception: " + ex.getMessage());
  System.out.println("Response Status Code: " + ex.getStatusCode());
  System.out.println("Error Code: " + ex.getErrorCode());
  System.out.println("Error Type: " + ex.getErrorType());
  System.out.println("Request ID: " + ex.getRequestId());
  System.out.println("XML: " + ex.getXML());
}
 
return results;
}

A tecnologia Java não tem os mesmos recursos de serialização XML integrados que a estrutura .NET, portanto, a JDOM API é usada para gerar o documento XML. JDOM é similar a DOM, mas fornece uma Java API simples para analisar, manipular e apresentar XML. Consulte Recursos para mais informações sobre como usar JDOM.

A classe PurchaseOrderSerializer é responsável por desserializar o conteúdo XML da mensagem para uma classe Java. Use JDOM para analisar o conteúdo XML, como na Listagem 21. (À medida que você seguir esse código, é útil consultar o esquema referente à ordem de compra na Listagem 7.)


Listagem 21. A classe PurchaseOrderSerializer
	
public class PurchaseOrderSerializer {

public CustomerOrderEntity deserializePO(MessageQueueEntity message) {
  CustomerOrderEntity order = null;
  
  String xml = message.getMessageBody();
  System.out.println("Purchase Order:\n" + xml);
  
  try {
           // Create input source from string containing XML
           InputSource xmlIS = new InputSource();
           xmlIS.setCharacterStream(new StringReader(xml));
           
           // Initialize SAX Builder object
           SAXBuilder builder = new SAXBuilder();
 
           // Build JDOM Document object from input source
           Document doc = builder.build(xmlIS);
           Element rootElem = doc.getRootElement();
           
           // get order id
           String id = rootElem .getChildText("Id");        
           
           // create customer order 
           order = new CustomerOrderEntity(id);
           
           // set order date
           String dateStr = rootElem.getChildText("OrderDate");
           order.setOrderDate(DateUtil.getDate(dateStr));
            
           // get company (customer) address element node and parse it
           Element addrElem = rootElem.getChild("Company");
           this.setCompanyAddress(order, addrElem);

           // get vendor address element node and parse it
           addrElem = rootElem.getChild("Vendor");
           this.setVendorAddress(order, addrElem);

           // get order items list and parse it
           Element itemsElem = rootElem.getChild("Items");
           this.setOrderItems(order, itemsElem);
           
           System.out.println(order.toString());
  } catch (IOException e) {
           e.printStackTrace();
  } catch (NullPointerException e) {
           e.printStackTrace();
  } catch (JDOMException e) {
           e.printStackTrace();
  }
  return order;
}
 
private void setVendorAddress(CustomerOrderEntity order, Element addrElem) {
  // get data from xml
  String coName = addrElem.getChildText("CompanyName");
  String streetAddress = addrElem.getChildText("StreetAddress");
  String city = addrElem.getChildText("City");
  String state = addrElem.getChildText("State");
  String zipCode = addrElem.getChildText("ZipCode");
  
  AddressEntity coAddress = order.getVendorAddress();
   
  // build address entity object using data read from xml
  AddressEntity coAddress = order.getCompanyAddress();
  coAddress.setCity(city);
  coAddress.setCompanyName(coName);
  coAddress.setStreetAddress(streetAddress);
  coAddress.setState(state);
  coAddress.setZipCode(zipCode);
}
  
private void setCompanyAddress(CustomerOrderEntity order, Element addrElem) {
  // get data from xml
  String coName = addrElem.getChildText("CompanyName");
  String streetAddress = addrElem.getChildText("StreetAddress");
  String city = addrElem.getChildText("City");
  String state = addrElem.getChildText("State");
  String zipCode = addrElem.getChildText("ZipCode");
  
  // build address entity object using data read from xml
  AddressEntity coAddress = order.getCompanyAddress();
  coAddress.setCity(city);
  coAddress.setCompanyName(coName);
  coAddress.setStreetAddress(streetAddress);
  coAddress.setState(state);
  coAddress.setZipCode(zipCode);
}
 
private void setOrderItems(CustomerOrderEntity order, Element itemsElem) {
  List itemList = itemsElem.getChildren();
  if (itemList == null) return;
  
  // iterate through all items in collection
  for (int index = 0; index < itemList.size(); index++) {
           // get current element
           Element curElem = (Element) itemList.get(index);
           
           // get item values
           String itemId = curElem.getAttributeValue("Id");
           String itemName = curElem.getAttributeValue("Name");
           String quantity = curElem.getAttributeValue("Quantity");
           
           // create order item
           CustomerOrderDetailEntity detail = new CustomerOrderDetailEntity();
           detail.setItemId(itemId);
           detail.setItemName(itemName);
           detail.setQuantity(Integer.parseInt(quantity));
  
           // add order item to order summary
           order.addItem(detail);
  }
}
}

Em seguida, crie o resumo de ordens da ordem de compra. Listagem 22 mostra o código.


Listagem 22. O método getOrderSummaryForCustomerOrder()
	
public OrderSummaryEntity getOrderSummaryForCustomerOrder(
	CustomerOrderEntity customerOrder) {
	
	if (customerOrder == null) return null;
	
	// create order
	OrderSummaryEntity orderSummary = new OrderSummaryEntity();
	orderSummary.setOrderDate(new Date());
	orderSummary.setReferenceId(customerOrder.getId());
	
	// set addresses
	orderSummary.setCompanyAddress(customerOrder.getVendorAddress());
	orderSummary.setCustomerAddress(customerOrder.getCompanyAddress());
	
	// add items
	Iterator<CustomerOrderDetailEntity> itemIter = customerOrder.getItems();
	while(itemIter.hasNext()) {
		CustomerOrderDetailEntity item = itemIter.next();
		
		OrderSummaryDetailEntity detail = new OrderSummaryDetailEntity();
		detail.setItemId(item.getItemId());
		detail.setItemName(item.getItemName());
		detail.setQuantity(item.getQuantity());
		
		orderSummary.addItem(detail);
	}
	
	return orderSummary;
}			

Em seguida, é preciso serializar o OrderSummaryEntity para XML. Use JDOM para serializar a mensagem, como na Listagem 23. (É útil consultar o esquema referente ao resumo de ordens na Listagem 8.)


Listagem 23. A classe OrderSummarySerializer
	
public class OrderSummarySerializer {
	public String serializeOrder(OrderSummaryEntity order) {
		Document doc = new Document();
		
		Element rootElem = new Element("OrderSummary");
		doc.addContent(rootElem);
		
		// add id
		Element idElem = new Element("OrderId");
		idElem.setText(order.getOrderId());
		rootElem.addContent(idElem);
		
		// add reference id
		Element referenceIdElem = new Element("ReferenceId");
		referenceIdElem.setText(order.getReferenceId());
		rootElem.addContent(referenceIdElem);
		
		// add order date
		Element dateElem = new Element("OrderDate");
		String dateStr = DateUtil.getDateString(new Date());
		dateElem.setText(dateStr);		
		rootElem.addContent(dateElem);
		
		// set company address
		Element addrElem = this.getElementForAddress("CompanyAddress", 
			order.getCompanyAddress());
		rootElem.addContent(addrElem);
		
		// set customer address
		addrElem = this.getElementForAddress("CustomerAddress", 
			order.getCustomerAddress());
		rootElem.addContent(addrElem);
		
		// iterate through all items and add each item to order
		Element itemsElem = new Element("Items");
		Iterator<OrderSummaryDetailEntity> itemIter = order.getItems();
		while(itemIter.hasNext()) {
			OrderSummaryDetailEntity item = itemIter.next();
			
			Element itemElem = new Element("Item");
			itemElem.setAttribute("ItemId", item.getItemId());
			itemElem.setAttribute("ItemName", item.getItemName());
			String quantityStr = String.valueOf(item.getQuantity());
			itemElem.setAttribute("Quantity", quantityStr);
			
			itemsElem.addContent(itemElem);
		}
		rootElem.addContent(itemsElem);
		
		// convert xml document to string
		XMLOutputter outp = new XMLOutputter();
		StringWriter strWriter = new StringWriter();        
		try {
			outp.output(doc, strWriter);
		} catch (IOException e) {
			e.printStackTrace();
		}		
		return strWriter.toString();
	}

	private Element getElementForAddress(String elemName, AddressEntity address) {
		Element addrElem = new Element(elemName);
		
		String coName = address.getCompanyName();
		String streetAddress = address.getStreetAddress();
		String cityName = address.getCity();
		String stateName= address.getState();
		String zipCode = address.getZipCode();
		
		Element coElem = new Element("CompanyName");
		coElem.setText(coName);
		addrElem.addContent(coElem);
		
		Element streetElem = new Element("StreetAddress");
		streetElem.setText(streetAddress);
		addrElem.addContent(streetElem);
		
		Element cityElem = new Element("City");
		cityElem.setText(cityName);
		addrElem.addContent(cityElem);
		
		Element stateElem = new Element("State");
		stateElem.setText(stateName);
		addrElem.addContent(stateElem);
		
		Element zipCodeElem = new Element("ZipCode");
		zipCodeElem.setText(zipCode);
		addrElem.addContent(zipCodeElem);
		
		return addrElem;
	}
}			

Envie a mensagem XML à fila Amazon SQS usando Amazon Java API. Listagem 24 mostra como enviar a mensagem.


Listagem 24. O método sendMessage()
	
protected boolean sendMessage(String queueName, String messageBody) {
boolean result = false;
try {
	String accessKeyId = AppConfig.getProperty("AmazonAccessKeyID");
	String secretAccessKey =  AppConfig.getProperty("AmazonSecretAccessKey");

	AmazonSQS service = new AmazonSQSClient(accessKeyId, secretAccessKey);
	
	SendMessageRequest request = new SendMessageRequest();
	request.setQueueName(queueName);
	request.setMessageBody(messageBody);
	
	SendMessageResponse response = service.sendMessage(request);
	// Send Message Response
	if (response.isSetSendMessageResult()) {
		System.out.println("\tSend Message Result");
		SendMessageResult sendMessageResult = response.getSendMessageResult();
		if (sendMessageResult.isSetMessageId()) {
			System.out.println("\t\tMessageId: " + 
				sendMessageResult.getMessageId());
			result = true;
		}
	} 		
} catch (AmazonSQSException ex) {
	System.out.println("Caught Exception: " + ex.getMessage());
	System.out.println("Response Status Code: " + ex.getStatusCode());
	System.out.println("Error Code: " + ex.getErrorCode());
	System.out.println("Error Type: " + ex.getErrorType());
	System.out.println("Request ID: " + ex.getRequestId());
	System.out.println("XML: " + ex.getXML());
}

return result;
}

Para finalizar, é preciso excluir o item da fila de ordens de compra da fila Amazon SQS. Listagem 25 mostra como excluir a mensagem.


Listagem 25. O método deleteMessage()
	
protected boolean deleteMessage(String queueName, String handle) {
boolean result = false;

try {
	String accessKeyId = AppConfig.getProperty("AmazonAccessKeyID");
	String secretAccessKey =  AppConfig.getProperty("AmazonSecretAccessKey");

	AmazonSQS service = new AmazonSQSClient(accessKeyId, secretAccessKey);
	DeleteMessageRequest request = new DeleteMessageRequest();
	request.setQueueName(queueName);
	request.setReceiptHandle(handle);
	
	DeleteMessageResponse response = service.deleteMessage(request);

	// Delete Message Response
	if (response.isSetResponseMetadata()) {
		// Response Metadata
		ResponseMetadata  responseMetadata = response.getResponseMetadata();
		if (responseMetadata.isSetRequestId()) {
			System.out.print("RequestId: " + 
				responseMetadata.getRequestId());
			result = true;
		}
	} 
} catch (AmazonSQSException ex) {
	System.out.println("Caught Exception: " + ex.getMessage());
	System.out.println("Response Status Code: " + ex.getStatusCode());
	System.out.println("Error Code: " + ex.getErrorCode());
	System.out.println("Error Type: " + ex.getErrorType());
	System.out.println("Request ID: " + ex.getRequestId());
	System.out.println("XML: " + ex.getXML());
}

return result;
}


Testando a solução

Agora, você está pronto para testar a solução. Para testar a solução, envie uma ordem referente a um item para o qual não há inventário suficiente. Em seguida, é possível rastrear todo o processo:

  • Enviando a ordem
  • Revendedor que coloca a ordem como pedido em atraso e cria a ordem de compra
  • Manufatura recebe a ordem e envia o resumo de ordens ao revendedor
  • Revendedor recebe o resumo de ordens e processa o pedido em atraso

O cliente revendedor na Figura 6. mostra os níveis de inventário antes de uma nova ordem ser feita.


Figura 6. Navegar no inventário

Figura 7 mostra a janela de envio de ordem.


Figure 7. Enviar a ordem

Figura 8 mostra a janela Browse Orders .


Figura 8. Navegando em ordens

Após a nova ordem ser feita, a janela na Figura 9 mostrará a saída dos serviços de preenchimento de ordem quando a ordem for colocada como pedido em atraso.


Figura 9. O preenchimento da ordem pelo revendedor e serviço de gerenciamento de inventário

Após a nova ordem ser feita, a janela na Figura 10 mostrará o conteúdo da fila de mensagens POQueue .


Figura 10. Visualizar a fila de mensagens

O fabricante recebe a ordem de compra da fila de mensagens e a processa. Figura 11 mostra a saída do sistema de processamento de ordem do fabricante.


Figura 11. O serviço de gerenciamento de ordem do fabricante


Conclusão

Este artigo mostra como utilizar XML e o serviço da Web Amazon SQS para integrar aplicativos de negócios corporativos. Combinar a extensibilidade de XML com Amazon SQS resulta em um aplicativo altamente escalável e flexível. Os benefícios principais dessa solução são a escalabilidade, a extensibilidade e o esforço de integração mínimo. A integração não precisou de nenhuma consideração especial de firewall ou de segurança. O benefício mais recente desta solução— e um motivador principal para serviços da Web—é que a solução funciona entre plataformas e é agnóstica de tecnologia. O fabricante e o revendedor podem manter suas plataformas de tecnologia existentes enquanto integram seus processos de negócios para impulsionar a eficiência operacional e o retorno sobre investimento (ROI).

Esta solução tem poucas limitações. Primeiramente, o tamanho máximo de um corpo da mensagem de Amazon SQS é de 8 KB. É possível contornar essa situação com várias soluções possíveis:

  • Use Amazon Simple Storage Service (Amazon S3) para armazenar o documento XML grande e colocar um identificador no item Amazon S3 na mensagem Amazon SQS.
  • Use Amazon SimpleDB para armazenar os dados estruturados e inserir um identificador nos itens da mensagem Amazon SQS.

A segunda limitação é a abordagem de consistência eventual que Amazon usa com a fila. É uma coisa boa e ruim ao mesmo tempo, mas é evidente que Amazon acredita que as coisas boas superam de longe as ruins. A limitação mais recente da solução é que não existe nenhuma prioridade ou abordagem FIFO. Novamente, isso é intencional por parte do Amazon, já que fornece uma solução mais escalável, confiável e altamente disponível.

Se você usar XML para troca de dados no corpo da mensagem, as melhores práticas recomendarão que se execute a validação XML Schema (XSD) para assegurar que o remetente e o destinatário falem a mesma língua. Assim como com qualquer projeto de integração XML, o remetente e o destinatário precisam concordar com um esquema comum.



Downloads

DescriçãoNomeTamanhoMétodo de download
C# projects for the reseller applicationsNETSolution.zip223KBHTTP
Java project for the manufacturer applicationsJavaSolution.zip24KBHTTP
Contains the configuration scriptsDbScripts.zip1KBHTTP

Informações sobre métodos de download


Recursos

Aprender

  • Documentação técnica de Amazon SQS: consulte as informações na biblioteca Amazon SQS.

  • Documentação JDOM: obtenha informações sobre a biblioteca JDOM e essa solução baseada em Java para acessar, manipular e apresentar dados XML de código Java.

  • Connecting to the cloud, Part 3: Cloud governance and security: Secure the HybridCloud application (Mark O'Neill, developerWorks, junho de 2009): encontre uma boa descrição das chaves usadas com Amazon SQS e explore como configurar políticas que protegem informações sensíveis e monitoram o acesso e o uso de seus aplicativos na nuvem. Na Parte 1 desta série, observe um exemplo híbrido com infraestrutura e serviços de computação em nuvem (Mark O'Neill, developerWorks, março de 2009). Na Parte 2, desenvolva esse aplicativo híbrido (Mark O'Neill, developerWorks, abril de 2009).

  • Consistência eventual: consulte a entrada no blog de Werner Vogels (Amazon CTO) sobre consistência eventual para informações sobre a lógica de design do Amazon SQS.

  • Simplifique a programação XML com JDOM (Wes Biggs e Harry Evans, developerWorks, maio de 2001): JDOM é similar a DOM, mas fornece uma Java API simples para analisar, manipular e apresentar XML. Saber como usar essa API de software livre torna a manipulação de documentos XML mais fácil para desenvolvedores Java.

  • Certificação XML da IBM: Descubra como se tornar um Desenvolvedor Certificado pela IBM em XML e tecnologias relacionadas.

  • Biblioteca técnica de XML: Consulte a zona de XML para obter uma ampla gama de artigos técnicos e dicas, tutoriais, padrões e Redbooks da IBM.

  • eventos técnicos e webcasts do developerWorks : Mantenha-se atualizado em relação à tecnologia nessas sessões.

  • Podcasts do developerWorks : Ouça entrevistas e discussões interessantes para desenvolvedores de software.

Obter produtos e tecnologias

Discutir

Sobre o autor

Photo of Brian Stewart

Brian J. Stewart é atualmente o consultor principal da Aqua Data Technologies, uma empresa fundada com foco em gerenciamento de conteúdo, tecnologias XML e sistemas Web e cliente-servidor corporativos. Ele arquiteta e desenvolve soluções corporativas com base nas plataformas Java EE e Microsoft .NET. Brian mantém um blog em BrianJStewart.com.

Ajuda para Relatar Abuso

Relatar abuso

Obrigado. Esta entrada foi sinalizada para atenção do moderador.


Ajuda para Relatar Abuso

Relatar abuso

Falha no envio do Relatório de abuso. Tente novamente mais tarde.


developerWorks: Registre-se


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos de uso do developerWorks.

 


Na primeira vez que você efetua sign in no developerWorks, um perfil é criado para você. Informações selecionadas do seu perfil developerWorks são exibidas ao público, mas você pode editá-las a qualquer momento. Seu primeiro nome, sobrenome (a menos que escolha ocultá-los), e seu nome de exibição acompanharão o conteúdo que postar.

Selecione seu nome de exibição

Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

(Deve possuir de 3 a 31 caracteres.)


Ao clicar em Enviar, você concorda com os termos de uso do developerWorks.

 


Classificar este artigo

Comentários

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=
ArticleID=642817
ArticleTitle=Utilizando Amazon Web Services para Integração de Aplicativos Corporativos
publish-date=03212011
author1-email=BrianJStewart@AquaDataTech.com
author1-email-cc=

Conheça a IBM da sua cidade

Virtual Branch Office Brasil

A IBM está mais perto do que você imagina!


Tags

Help
Use o campo de pesquisa para encontrar todos os tipos de conteúdo no My developerWorks com essa tag.

Use a barra de rolagem para ver mais ou menos tags.

Tags populares mostra as principais tags para esta zona de conteúdo em particular (por exemplo, Java technology, Linux, WebSphere).

Minhas tags mostra suas tags para esta zona de conteúdo em particular (por exemplo, Java technology, Linux, WebSphere).

Use o campo de pesquisa para localizar todos os tipos de conteúdo no Meu developerWorks com essa tag. Tags populares mostra as tags principais para essa zona de conteúdo particular (por exemplo, tecnologia Java, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere). Minhas tags mostra as suas tags para essa zona de conteúdo em particular (por exemplo, tecnologia Java, Linux, WebSphere).