Integração de aplicações em Luiz Eduardo Borges http://ark4n.wordpress.com/ Sumário ● Integração de aplicações ● Aplicações distribuídas ● Camada de comunicação ● Formatos de dados ● Aplicações externas Integração de aplicações (tradicional) Aplicação A Aplicação B Bibliotecas Dados e regras de negócio precisam estar em um SGBD para garantir a integridade e sigilo. Dados Funções disponíveis para as aplicações. Ambiente que requer muita administração para se manter organizado. Integração através de middleware Aplicação A Regras de negócio podem ficar em componentes. Aplicação B Middleware Dados Funções disponíveis para todas as aplicações. O ambiente requer muita padronização para se manter organizado. Middleware ● ● ● É uma camada de software que conecta componentes ou aplicações, tendo como o objetivo a interoperabilidade. Várias opções: – ZOPE (Z Object Publishing Environment) – WSGI (Web Server Gateway Interface) – Twisted – Muitos outros O próprio Python pode ser encarado como um middleware. Aplicações distribuídas Arquiteturas: ● Computacional ● De recursos ● De aplicação ou híbrida Modelo computacional O servidor distribui as requisições e centraliza os resultados. A B C D Os outros nós (workers) recebem as tarefas e calculam os resultados. Modelo de recursos A B C D Os servidores recebem as requisições e devolvem os resultados. Os clientes enviam as requisições e recebem os resultados. E F G H Modelo híbrido ou de aplicação A aplicação se confunde com a infraestrutura, provendo os recursos. A B C D Cada nó pode atuar como servidor e cliente, inclusive ao mesmo tempo. Modelos (comparação) Computacional Recursos Híbrido Escalabilidade Média Alta Alta Complexidade Baixa Média Alta Tolerância a falhas Média Alta Alta Principal Aplicação Processamento memória Infra Arquivos Exemplo SETI@home Servidores Web P2P Aplicações distribuídas (requisito I) Primeiro requisito: definir a forma de comunicação entre os nós. A B C D Aplicações distribuídas (requisito II) Segundo requisito: manter os metadados sobre os nós, usuários, arquivos e outros recursos. A B C D Aplicações distribuídas (requisito III) Terceiro requisito: fazer o monitoramento e controle dos componentes do sistema. A B C D Aplicações distribuídas (requisito IV) A B C D Quarto requisito: manter a segurança (sigilo, integridade e disponibilidade) dos dados e sistemas envolvidos. Camada de comunicação A camada torna transparente os protocolos de rede. Rede Máquina Máquina Framework Framework Aplicação Aplicação Camadas de comunicação em Python ● PYRO ● XML-RPC ● Socket PYRO (Python Remote Objects) Implementa: ● ● ● ● Um protocolo que permite a execução remota via TCP/IP de métodos de um objeto. Envio de estruturas de dados “serializáveis” como parâmetros. Servidor de nomes que facilita a localização automática dos métodos. Validadores para verificar as credenciais do cliente. PYRO (servidor) import numpy import Pyro.core class Dist(Pyro.core.ObjBase): def fft(self, l): return numpy.fft.fft(l) # Inicia a thread do servidor Pyro.core.initServer() # Cria o servidor daemon = Pyro.core.Daemon() # Publica o objeto uri = daemon.connect(Dist(),'dist') # Coloca o servidor em estado operacional daemon.requestLoop() Classe do objeto que será publicado na rede pelo PYRO. Método que calcula a transformada de Fourier. PYRO (cliente) # -*- coding: utf-8 -*import numpy import Pyro.core # Dados de teste dados = numpy.random.rand(100) # Cria um objeto local para acessar o objeto remoto proxy = Pyro.core.getProxyForURI('PYROLOC://127.0.0.1/dist') # Evoca um método do objeto distribuído print proxy.fft(dados) XML-RPC Implementa: ● ● ● Protocolo de execução remota de procedimentos. Transferências de dados em XML usando HTTP ou HTTPS (criptografado) como protocolo de transporte. Suporte a tipos básicos: inteiro, ponto flutuante, texto, ... XML-RPC (servidor) import numpy from SimpleXMLRPCServer import SimpleXMLRPCServer # Cria um servidor server = SimpleXMLRPCServer(('localhost', 8888)) server.register_introspection_functions() def fft(l): return [ float(x) for x in numpy.fft.fft(l) ] server.register_function(fft) # Inicia o loop do servidor server.serve_forever() Conversão para tipos que o XML-RPC aceita. XML-RPC (cliente) import numpy import xmlrpclib Conversão para tipos que o XML-RPC aceita. # Dados de teste dados = [ float(x) for x in numpy.random.rand(100) ] server = xmlrpclib.Server("http://localhost:8888") # Evoca o procedimento remoto print server.fft(dados) Socket Implementa: ● ● Acesso de baixo nível a biblioteca de sockets que disponível em praticamente qualquer sistema operacional atual. Conexões ponto a ponto vai TCP/IP. Socket (servidor I) import import import import cPickle socket threading numpy Classe que implementa as threads para o servidor. class Server(threading.Thread): def __init__(self, skt): self.skt = skt threading.Thread.__init__ (self) def run(self): # Recebe os dados rec = self.skt.recv(5000) # Calcula o resultado ff = numpy.fft.fft(cPickle.loads(rec)) # Retorna a resposta self.skt.send(cPickle.dumps(ff)) Método que é executado na thread. Dados foram serializados no cliente. Continua... Socket (servidor II) # cria um socket INET STREAM server = socket.socket( socket.AF_INET, socket.SOCK_STREAM) # Associa o socket a uma porta na interface de rede server.bind((socket.gethostname(), 8000)) # Passa a "ouvir" a porta server.listen(5) while True: # aceita acesso externo (skt, addr) = server.accept() svr =Server(skt) svr.start() Socket (cliente) import cPickle import socket import numpy # Dados dados = numpy.random.rand(100) # cria um socket INET STREAM svr = socket.socket( socket.AF_INET, socket.SOCK_STREAM) # Conecta na interface de rede svr.connect((socket.gethostname(), 8000)) svr.send(cPickle.dumps(dados)) # Recebe a resposta rec = svr.recv(5000) print cPickle.loads(rec) Os resultados foram serializados no servidor. Comunicação (comparação) PYRO XML-RPC Socket Performance Alta Baixa Alta Portabilidade Baixa Alta Alta Escalabilidade Alta Baixa Depende da aplicação Complexidade Baixa Média Alta Dependências Média Baixa Baixa YAML (YAML Ain't a Markup Language) Implementa: ● ● ● ● Formato de serialização de dados para texto, amigável para humanos. Representação de dados através de combinações de listas, dicionários e escalares. Convenções de sintaxe similares as linguagens dinâmicas, com forte influência do Python. Um superset do JSON (JavaScript Object Notation). YAML (exemplo) - Artista: King Crimson Faixas: - Starless - Frature - Red - Lizard - Artista: Genesis Faixas: - Supper's Ready - In The Cage - The Lamia Documento YAML [{'Artista': 'King Crimson', 'Faixas': ['Starless', 'Frature', 'Red', 'Lizard']}, {'Artista': 'Genesis', 'Faixas': ["Supper's Ready", 'In The Cage', 'The Lamia']}] Estrutura Python Formatos (comparação) YAML / JSON XML (c)Pickle Performance Média Baixa Alta Portabilidade Alta Alta Baixa Escalabilidade Média Alta Alta Complexidade Baixa Média Baixa Dependências Média Baixa Baixa Aplicações externas Aplicações “pythônicas”: ● BrOffice.org ● Blender ● GIMP ● Inkscape ● PostgreSQL BrOffice.org Implementa: ● ● Suporte ao Python como linguagem de macro, permitindo a automatização de tarefas e a construção de extensões (add ons). Serviço para atender conexões, através de uma API chamada UNO (Universal Network Objects). BrOffice.org (serviço) Interpretador PyUNO Python UNO Bridge Aplicação BrOffice.org Aceita conexões remotas via named pipes ou sockets. BrOffice.org (exemplo I) # -*- coding: latin1 -*# Para iniciar o BrOffice.org como servidor: # swriter.exe -headless # "-accept=pipe,name=py;urp;StarOffice.ServiceManager" import os import uno from com.sun.star.beans import PropertyValue # Dados... mus = [('Artista', 'Faixa'), ('King Crimson', 'Starless'), ('Yes', 'Siberian Khatru'), ('Led Zeppellin', 'No Quarter'), ('Genesis', 'Supper\'s Ready')] rows = len(mus) cols = len(mus[0]) Continua... BrOffice.org (exemplo II) # Inicio do "Boiler Plate"... # Contexto de componente local loc = uno.getComponentContext() # Para resolver URLs res = loc.ServiceManager.createInstanceWithContext( 'com.sun.star.bridge.UnoUrlResolver', loc) # Contexto para a URL con = res.resolve('uno:pipe,name=py;urp;StarOffice.ComponentContext') # Documento corrente desktop = con.ServiceManager.createInstanceWithContext( 'com.sun.star.frame.Desktop', con) # Fim do "Boiler Plate"... Continua... BrOffice.org (exemplo III) # Cria um documento novo no Writer doc = desktop.loadComponentFromURL('private:factory/swriter', '_blank', 0, ()) # Cursor de texto cursor = doc.Text.createTextCursor() # Muda propriedades cursor.setPropertyValue('CharFontName', 'Verdana') cursor.setPropertyValue('CharHeight', 20) cursor.setPropertyValue('CharWeight', 180) doc.Text.insertString(cursor, 'Músicas favoritas\n', 0) Texto inserido # Cria tabela tab = doc.createInstance('com.sun.star.text.TextTable') tab.initialize(rows, cols) doc.Text.insertTextContent(cursor, tab, 0) Continua... BrOffice.org (exemplo IV) # Preenche a tabela for row in xrange(rows): for col in xrange(cols): cel = chr(ord('A') + col) + str(row + 1) tab.getCellByName(cel).setString(mus[row][col]) Tabela # Propriedades para exportar o documento props = [] p = PropertyValue() p.Name = 'Overwrite' p.Value = True # Sobrescreve o documento anterior props.append(p) p = PropertyValue() p.Name = 'FilterName' p.Value = 'writer_pdf_Export' # Writer para PDF props.append(p) Continua... BrOffice.org (exemplo V) # URL de destino url = uno.systemPathToFileUrl(os.path.abspath('musicas.pdf')) # Salva o documento como PDF doc.storeToURL(url, tuple(props)) # Fecha o documento doc.close(True) Arquivo de saída Referências PYRO: ● http://pyro.sourceforge.net/ Socket Programming HOWTO: ● http://www.amk.ca/python/howto/sockets/ YAML Cookbook: ● http://yaml4r.sourceforge.net/cookbook/ Python – OpenOffice.org Wiki: ● http://wiki.services.openoffice.org/wiki/Python Integração de aplicações em Luiz Eduardo Borges http://ark4n.wordpress.com/ Fim