Beruflich Dokumente
Kultur Dokumente
Coordenadores Antnio Silva Fernando Martins Editor Fbio Domingos Jorge Paulino Design Srgio Alves Twitter: @scorpion_blood Redaco Andr Lage, Augusto Manzano, Bruno Lopes, Bruno Pires, Carlos Rodrigues, Fbio Domingos, Flvio Geraldes, Joo Tito Lvio, Niko Neugebauer, Nuno Godinho
Cada vez mais exigido rigor em todos os aspectos nas mais variadas reas. A programao no excepo, tanto mais se pensarmos que cada vez mais a tecnologia faz parte da vida das pessoas. Nos dias que correm natural exigir que qualquer aplicao no possua erros de compilao nem os famosos warnings. Todavia estes so sem dvida os mais fceis de corrigir. O problema quando aparecem os denominados erros de runtime. Algo que o programador no previu no seu algoritmo e que se pode tornar numa autntica bomba, capaz de detonar o programa todo. E se pensarmos que numa aplicao de contabilidade, o que poder acontecer ser necessrio repetir a operao, no caso de uma aplicao de uma nave espacial, por exemplo, o caso de uma diviso por zero que no seja protegida, quando a nave est a calcular o ngulo de entrada na atmosfera, pode determinar a diferena entre o prejuzo de milhes e o lucro, talvez at entre a vida e a morte.
Ao contrrio de muitas outras reas, a programao no ainda alvo da chamada prova cientfica, apesar de Informtica ser considerada uma cincia. Se perguntarmos a um Engenheiro Civil a razo porque determinada ponte no ca, ele explicarnos- com clculos matemticos que garantem a estabilidade da ponte. Se perguntarmos grande maioria dos Programadores ou at Engenheiros Informticos o porqu do programa funcionar correctamente, muito dificilmente obteremos uma resposta com prova cientfica.
Staff Antnio Santos, Fbio Canada Pedro Martins, Sara Santos Contacto revistaprogramar@portugal-aprogramar.org Website http://www.revista-programar.info ISSN 1 647-071 0
Para percebermos o parte do drama basta ver problemas de segurana bsicos que existem em muitas aplicaes na Web e fora dela. Muitas vezes a criao de um programa deixa de ser uma sequncia de passos j definidos, para ser inspirao da musa da programao, e onde se escrevem linhas e linhas de cdigo, simples frutos de sbita (des)inspirao. Em vez de programadores passam a poetas, que se inspiram na sua musa, e que em vez de Redondilhas criam Centilhas. Muitas vezes sem perceberem que esto a fazer algo e a desfazer nas linhas seguintes, e onde s est a ser gasto processamento.
A verdade que os erros no vo desaparecer completamente, porque continumos a ver erros na nossa civilizao que custam dinheiro e at vidas. Todavia, e felizmente o nmero de pontes, avies e outras invenes no caem com tanta frequncia como caem as aplicaes. Porque a o problema est muitas vezes no ser humano que verificou, e que fez um erro na verificao. Por isso era provvel que consegussemos melhores resultados se fosse feita uma aposta forte no clculo e correco de algoritmos.
A revista PROGRAMAR um projecto voluntrio sem fins lucrativos. Todos os artigos so da responsabilidade dos autores, no podendo a revista ou a comunidade ser responsvel por alguma impreciso ou erro. Para qualquer dvida ou esclarecimento poder sempre contactar-nos.
TEMA DE CAPA
7 Introduo ao Ruby on Rails Conhea as bases da tecnologia Ruby on Rails para desenvolvimento de pginas web. Carlos Rodrigues.
A PROGRAMAR
30 Lua - Parte 10 A continuao de um excelente artigo sobre LUA, uma linguagem de programao pouco conhecida. Nesta dcima parte, saiba como embeber a linguagem LUA em programas escritos em C e C++, bem como pode utilizar co-rotinas. Augusto Manzano. Criar um sistema RSS no Sharepoint atravs de uma lista de pginas Conhea uma forma simples e eficaz de atravs de RSS 2.0 fazer um response directamente numa pgina ASPX com um controlo de utilizador. Joo Tito Lvio. Introduo ao Objective-C e plataforma iOS Um artigo de introduo linguagem da Apple Objective-C e plataforma iOS utilizada nos dispositivos iPod Touch, iPhone e iPad. Bruno Pires. Atributos em C# Saiba como colocar metadados em aplicaes C# atravs de atributos. Flvio Geraldes
36
41
45
COLUNAS
51 Visual (NOT) Basic - Tipos Genricos Conhea estas estruturas que possuem bastantes vantagens sobre os Arrays. Fbio Domingos.
COMUNIDADES
59 AzurePT - Windows Azure Traffic Manager Conhea esta funcionalidade que possibilita a resoluo de vrios problemas relacionados com Cloud Computing. Nuno Godinho. SQLPort - Ferramentas gratuitas de trabalho com SQL Server Conhea algumas ferramentas gratuitas que podem facilitar e acelerar o trabalho com o SQL Server. Niko Neugebauer. NetPonto - NHibernate - do Import Package primeira iterao Como configurar e utilizar o NHibernate com FluentNHibernate para fazer a ponte entre as nossas classes em .NET e as nossas tabelas de bases de dados. Bruno Lopes. SharePointPT - Sandboxed Solutions em SharePoint Online 2010 Veja como criar Sandbox Solution utilizando os diversos Templates disponibilizados para o Visual Studio 2010. Andr Lage
67
74
84
EVENTOS
08 Ago - Damian Conway em Lisboa - Fun with Dead Languages 10 Ago - Summer Tech Refresh - Lisboa 16 Ago - XIV encontro da Comunidade SQLPort 27 Ago - Reunio presencial Comunidade NetPonto - Lisboa 24 Set - WordCamp Lisboa 2011 (Comunidade Portuguesa de WordPress) 24 Set - 2 Aniversrio da Comunidade NetPonto
Investigadores do ISEP desenvolvem software para tornar os motores de busca mais eficientes
Uma equipa de investigadores portugueses do Instituto Superior de Engenharia do Porto (ISEP) est envolvido num projecto da Microsoft que pretende desenvolver um novo software, com o objectivo de tornar os motores de busca mais rpidos, mais directos, mais eficazes e mais "inteligentes". A ideia permitir que os utilizadores da Internet obtenham informao mais concreta e direccionada, na altura da pesquisa. Ou seja, "o objectivo que os motores de busca sejam capazes de relacionar os parmetros pedidos pelos cibernautas e forneam respostas concretas, relacionando a informao como um raciocnio lgico", explicam os investigadores do ISEP. Actualmente, o software implementado nos motores de busca no capaz de absorver e processar a informao que exclusivamente destinada ao ser humano. O sistema apenas orientado para a apresentao de informao. O processamento e as concluses ficam para o utilizador. O software que est a ser desenvolvido pelo ISEP ser capaz de processar os dados pedidos pelo cibernauta e pesquisar os conceitos na web, no de forma isolada, mas relacionando-os entre si. Olhando para um caso concreto, pergunta "quais os apartamentos T2 existentes, com menos de 10 anos, para arrendar, a menos de 500 metros da Trindade, Plo Universitrio ou Salgueiros, por valor inferior a 500 euros?", o mais certo surgirem inmeros sites com referncias dispersas a cada um dos parmetros, mas nenhum site que os relacione entre si, devolvendo-nos todos os resultados que contenham as expresses "apartamentos T2, Plo universitrio, ou Salgueiros". No futuro, o objectivo que a pesquisa apenas devolva, de facto, a informao acerca dos apartamentos que renam todas as condies especificadas e com validade temporal. Fonte: Wintech
A integrao do Eclipse com ferramentas de desenvolvimento populares tambm foi melhorada no lanamento Indigo. Sobretudo, EGit 1.0 foi lanado como parte do ambiente padro do Eclipse, trazendo o muito necessrio suporte fora-da -caixa para o popular sistema de controlo da verso distribuda de git. O EGit construdo em cima da biblioteca JGit, a qual providencia uma implementao Java nativa da funcionalidade de cliente git. Para alm do suporte git includo, o Indigo tambm oferece uma interaco estreita com a ferramenta de gesto do projecto Maven atravs do novo projecto m2e. O Eclipse Indigo est disponvel para download a partir do site oficial Eclipse. O Eclipse vem com muitos sabores existem vrios pacotes para download com diferentes configuraes e componentes. Obviamente, pode utilizar o cliente Eclipse Marketplace includo para instalar componentes adicionais independentemente de qual pacote inicial for utilizado. Testmos o pacote padro de desenvolvimento Java em Mac OS X e conclumos que funciona como esperado. Para mais informaes sobre o lanamento, pode aceder ao anncio oficial do micro-site Indigo. A Fundao Eclipse est a fazer alguma angariao de fundos a par da actualizao. Se quer ajudar a fundao a atingir o seu objectivo de recrutar 500 novos Amigos de Eclipse, pode aceder pgina 500 Indigo. Fonte: http://arstechnica.com/open-source/news/2011/06/ eclipse-indigo-released-with-windowbuilder-gui-tool-and-egit10.ars (Traduo: Sara Santos)
Introduo
O que esperar deste artigo? Este artigo pretende servir como introduo construo de websites recorrendo tecnologia RubyOnRails. Como facilmente se entende, no possvel transmitir todos os pormenores inerentes a um processo desta complexidade num s artigo. Como tal, sero abordados alguns aspectos importantes, que permitiro a algum com total inexperincia com esta tecnologia, construir uma aplicao web simples com acesso a uma base de dados. Durante o artigo, e como os aspectos so focados de uma forma muito superficial, existem ligaes para que os temas analisados possam ser estudados e compreendidos com maior profundidade. No final do artigo encontram-se tambm algumas ligaes teis, bem como o local para descarregar o cdigo da aplicao que vai ser construda ao longo do artigo. ou no desta plataforma acaba tambm por se reflectir na forma que temos de organizar o nosso trabalho. Vejamos ento alguns dos factores que tornam esta tecnologia to apetecvel:
uma tecnologia livre O facto de no estar dependente de terceiros (leia-se empresas e tecnologias proprietrias), para muitos uma vantagem e um factor preponderante na escolha da tecnologia;
O que isto do Ruby on Rails e porque que me devo preocupar em conhecer esta tecnologia?
Por agora, vamos apenas considerar o RoR simplesmente como uma plataforma ou tecnologia de desenvolvimento web. Existem vrias tecnologias de desenvolvimento web, umas mais conhecidas, como o PHP, ASP clssico, ASP.NET, JSP, e outras em fase de expanso e ainda no to difundidas (embora esta tendncia esteja claramente mudana), como o caso do RoR.
Tem uma comunidade grande e activa - extremamente simples obter ajuda nas vrias comunidades existentes (tambm em Portugal: ver fim do artigo), e a maior parte das vezes algum j teve o mesmo erro/problema com que nos deparamos.
Ok, ento o RoR uma plataforma de desenvolvimento web, mas h muitas outras, porque que me devo interessar em aprender RoR? Os motivos so inmeros, por isso vamos apenas focar alguns que fazem parte de um conjunto bem maior, mas que ajudam a perceber que tipo de plataforma de desenvolvimento temos nossa frente. No final, o facto de gostarmos 7
Basta escolher a opo Download the Kit e correr o executvel que descarregado.
Instalao
Antes de continuarmos, vamos proceder instalao da plataforma. Desta forma alguns dos pequenos exemplos de cdigo podero ser testados medida que o artigo se vai desenvolvendo. Actualmente a plataforma mais utilizada para desenvolver RoR Mac OS X, mas vamos demonstrar a instalao em Windows, dado que este ser (em princpio) o sistema utilizado pela maioria dos leitores. Contudo ficam tambm ligaes para os stios onde se podero encontrar informao sobre a instalao desta plataforma em Mac e em Linux.
A instalao simples. Devemos apenas ter em ateno a opo que adiciona os executveis do Ruby, GIT e DevKit ao Path, para que mais tarde possamos cham-los a partir da linha de comandos.
Instalao em Windows
Estes dados servem para configurao do GIT (ver edio anterior da Revista) de modo a que possam utilizar repositrios GIT como por exemplo o GitHub (https://github.com).
Uma das abordagens seria instalar isoladamente estes itens, mas existe uma forma de instalar tudo isto (e mais ainda) de uma vez s, em Windows.
Atravs do menu iniciar temos acesso a uma linha de comandos carregada com o PATH dos executveis necessrios ao funcionamento da plataforma:
A sintaxe muito elegante e permite fazer cdigo simples e fcil de ler como este: Um dos comandos que interessa reter para j o irb. Este comando, disponvel na Prompt carregada com as ferramentas do RoR, abre uma consola de Ruby, onde podemos testar alguns dos exemplos que se seguem. maioridade = Maior de idade unless idade <18
A instruo unless funciona um pouco como o if, mas com a lgica invertida.
Nota: tanto em Mac como em Linux, necessrio instalar todos os elementos de forma separada, dado que at data no existe um mtodo de instalao que englobe todos os elementos necessrios.
Podemos ler a instruo anterior da seguinte forma: a varivel maioridade toma o valor Maior de idade a menos que a idade seja inferior a 18. Simples :) 3.times do
puts Portugal-a-Programar
Este o exemplo mais simples de um loop. A facilidade com que se pode ler permite que, mesmo que nunca se tenha visto Ruby, se perceba facilmente o que este pedao de cdigo faz. Repare-se que o nmero inteiro 3, considerado um objecto como qualquer outro, que tem mtodos que podem ser invocados, como neste caso, o mtodo times.
Introduo ao Ruby
De uma forma simples e rpida, Ruby uma linguagem de programao orientada por objectos, interpretada, fortemente tipada e ao mesmo tempo dinmica, com gesto automtica de memria. Surgiu no Japo em 1995, pelas mos de Yukihiro Matsumoto (tambm conhecido como Matz).
Temos ento, que o bloco de cdigo ( que termina no end) executado 3 vezes, tal como pode ser literalmente lido, quase como se fosse em ingls. Vamos ver com maior detalhe os loops um pouco mais frente. if pessoa.registada? puts bem-vindo else puts acesso negado end
Existem, hoje em dia, vrias tecnologias e linguagens baseadas em Ruby, como o JRuby, IronRuby, HotRuby, etc. Neste exemplo vemos a utilizao do ponto de interrogao
Em Ruby todos os tipos de dados so classes. Vamos apenas abordar algumas das classes mais utilizadas, pois seria impossvel abord-las a todas.
Referncia: http://www.ruby-doc.org/core/classes/String.html
Arrays Um array, em Ruby, definido pela classe Array. O primeiro ndice o 0 (zero). possvel utilizar o ndice -1 (menos um) para aceder ao ltimo elemento do Array, -2 (menos dois) para o penltimo, etc.
Numeric Como facilmente se depreende pelo nome, esta classe, representa valores numricos. Existem classes derivadas desta, como a Float, a Integer ou a BigNum. Tipicamente iro ser utilizadas as classes Double e Integer. Ex: Inicializao de um array vazio dados = Array.new Inicializao de um array com dois elementos dados =Array.new(1,2)
Um texto pode ser transformado em inteiro com o mtodo to_i e um nmero pode ser transformado em string (texto) com o mtodo to_s. Ex: a = 10 b=20.to_i * a
A adio de elementos ao array, faz-se com o operador << (duas vezes o sinal de menor): dados = Array.new(2,3,4)
dados << 5
Strings Como se depreende pelo nome, esta classe representa objectos de texto. Uma string pode delimitar-se com aspas () ou plicas (). O operador de concatenao composto por dois sinais de menor (<<). Ex: pais=Port pais << ugal puts pais
Hash Um Hash uma coleco de pares chave-valor. Funciona de forma parecida a um Array, com a diferena de que o ndice substitudo pela chave. muito frequente o uso de Hashes em Ruby (e tambm em Rails), e muito utilizados juntamente com Symbols (abordados de seguida).
Um Hash, define-se da seguinte forma: Resultado: Portugal 10 chave => valor ( sinal de igual e maior)
Um smbolo serve para representar nomes e textos perante o interpretador de Ruby. Um smbolo sempre constante num determinado contexto, no entanto pode representar num certo contexto uma classe, em outro contexto um mtodo, e ainda num terceiro contexto diferente uma varivel, mas ser sempre o mesmo objecto, da classe Symbol.
A herana entre classes faz-se utilizando o operador menor (<). Imagine-se que temos a classe Automovel que herda ou estende a classe Veiculo: class Automovel < Veiculo end
A definio de um objecto do tipo Symbol em Ruby tem sido alvo de discusses, mas parece que a definio resultante indica que um smbolo deve ser usado sempre que necessrio referenciar um nome (identificador, palavra-chave) mesmo que estejamos a falar de algo que no existe ainda no nosso cdigo. Confuso? Sim, concordo. Contudo com a utilizao de smbolos, o seu propsito vai ficando mais claro e torna-se at intuitivo.
Loops
While Um smbolo define-se colocando dois pontos (:) antes do seu nome. Os Smbolos so frequentemente usados como chaves em hashes. while condicao do #instrues end Referncia: http://www.ruby-doc.org/core/classes/Symbol.html No caso de ser apenas uma instruo, podemos uma verso ligeiramente diferente, que torna o cdigo bastante elegante e fcil de ler: instrucao while condicao
Uma classe define-se da seguinte forma: class NomeDaClasse #corpo da classe end
11
Resultado: 1 2 3
Extensibilidade
Imagine-se que necessitamos de estender a classe Integer e adicionar um mtodo que diga se um nmero positivo ou no. Vejamos ento como faze-lo: class Integer def positivo?
self>0
To simples como isto. Este tipo de alterao/acrescento de funcionalidades em runtime designa-se de Monkey Patching. Basicamente o mtodo each, percorrer todos os elementos da coleco e executa o cdigo contido dentro do bloco. Quem utiliza o foreach em outras linguagens est certamente a notar que falta algo.
Em outras linguagens (no dinmicas) este tipo de abordagem iria gerar um erro de Classe Duplicada, e a soluo seria estender a classe, criando uma nova classe que herdasse da classe integer e criar os novos mtodos ou fazer override dos mtodos j existentes na classe base.
Como que referenciamos o elemento actual dentro do bloco? Mais do que referenciar, temos de passar para dentro do bloco o item actual. Para isso, rodeamos por barras verticais ou pipes ( | ) o nome pelo qual queremos referenciar o objecto dentro do bloco.
Neste caso o mtodo positivo? ser um aumento da classe Integer, e passar a fazer parte da classe.
12
Ruby Gems
Uma gem no nada mais, nada menos do que uma biblioteca ou programa empacotado. Todas as gems tm um nome e uma verso. Pode ser feito um paralelismo com os ficheiros .dll no .NET ou os .jar no Java, embora existam diferenas.
Existem, assim, trs partes distintas do projecto, cada uma com responsabilidades prprias, e que interligadas permitem no s o funcionamento eficaz dos projectos, mas tambm facilitam de uma forma muito eficaz a manuteno dos projectos.
As Gems podem ser instaladas de forma fcil, bastando para isso existir uma ligao internet. A sua instalao funciona atravs de repositrios, de onde so descarregadas e instaladas.
Ao instalar o rails no Linux ou em Mac, foi necessrio, a certa altura, executar este comando: gem install rails
O Model, muitas vezes chamado de Domain visa representar o modelo de dados do projecto. tambm aqui grande parte da lgica deve residir, de modo enriquecer o modelo de dados. tambm o Model o responsvel pela persistncia de dados. Muitas vezes so utilizadas ferramentas de ORM acopladas ao Model, de modo a facilitar esta tarefa: NHibernate, Entity Framework, Hibernate, e o ORM que nos vai interessar particularmente: Active Record.
Este o comando para instalao de novas gems. A gem trazida do repositrio e instalada.
Um Controller um ponto de interaco do utilizador com a aplicao. Um controlador constitudo por aces (Actions) e cada aco representa um mtodo. o controlador o responsvel por validar dados e por fazer as chamadas necessrias ao Model de modo a passar-lhe dados ou simplesmente, a traz-los para a aplicao. Um controlador invoca as Views de modo a poder apresentar os dados ao utilizador.
possvel criamos as nossas prprias gems e at submetlas para o repositrio, para que outros as possam utilizar.
Uma View a representao visual da aplicao. Pode receber dados do Controller, e pode at ser uma representao visual do Model. sempre invocada por uma Action dentro de um Controller. aqui que reside a parte visual da aplicao.
Overview do MVC
Antes de passarmos anlise da framework Rails, que serve, juntamente com o Ruby, de base a esta tecnologia, vamos ver (ou rever, caso seja j um conceito familiar) como funciona uma aplicao MVC, dado que a framework funciona com base neste padro.
Como possvel perceber a partir da explicao anterior, existe uma total separao de conceitos, sendo que possvel alterar a interface da aplicao (alterando as Views) sem que o resto da aplicao sofra qualquer alterao. Da mesma forma, se existirem alteraes nas regras do negcio, ser o Model (e possivelmente tambm os Controllers) a sofrerem alteraes, mas as Views manter-se-o intactas, deixando a interface intacta. Se for necessrio alterar a forma de persistncia (por exemplo, trocar de motor de base de dados), ser a parte de persistncia do Model a nica seco do projecto a sofrer alteraes. Esta tarefa fica ainda mais simplificada se for utilizado um ORM com suporte a mltiplos motores de base de dados.
13
ainda possvel criar rotas personalizadas, de modo implementar prticas SEO, mas no sero abordadas neste artigo. Passemos ento ao Rails, enquanto Framework e plataforma de desenvolvimento web.
O MVC funciona atravs de rotas. Mas o que uma rota? Com uma tecnologia de desenvolvimento web convencional (e por convencional leia-se, no MVC), o url www.dominio.com/pasta/ficheiro.extensao leva-nos at um ficheiro chamado ficheiro.estensao, que se encontra realmente dentro de uma directoria chamada pasta, no servidor indicado por aquele endereo. Em MVC isto no acontece assim. Os caminhos so virtuais e so resolvidos pelo componente de gesto de rotas da plataforma. Em Rails e em grande parte das Frameworks MVC, a rota padro : Domnio/Controller/Action/Id, tambm representado por / Controller/Action/Id.
Quickstart Rails
Como j foi referido anteriormente, Ruby On Rails constitudo (entre outras coisas) por Ruby (a linguagem) e Rails (a Framework).
A framework - actualmente na verso 3.0 - surgiu em 2004 pelas mos de David Heinemeier Hansson ( http:// david.heinemeierhansson.com/ ).
Exemplo: www.dominio.com/Clientes/Detalhes/10
Utiliza o padro MVC e disponibiliza, out-of-the-box, funcionalidades como scaffolding (abordado mais frente), um ORM (Active Record), um servidor web (webBrick), entre outras funcionalidades e ferramentas, que permitem aos developers criarem, de uma forma rpida, aplicaes web.
Fazendo o paralelismo com o mapeamento acima, facilmente se percebe o seguinte: Controller: Clientes Action: Detalhes Id: 10 Ento temos que estamos a invocar a aco Detalhes, que um mtodo do Controlador Clientes e estamos a passarlhe o id 10.
O que esta Action provavelmente faz aceder ao Model e trazer os dados do cliente com o id 10. Depois deve passar os dados, devidamente formatados, para uma View, que invocada pela Action.
DRY Significa Dont Repeat Yourself, mas tambm poNo existe, necessariamente, nenhuma pasta chamada clientes, ou detalhes, nem um ficheiro com nome 10, mas sim uma rota que capaz de pegar num url e de o transformar numa chamada a um mtodo (Action) de uma classe (Controller) passando-lhe um (ou mais) parmetros. de ser lido na forma literal, como cdigo seco. Cdigo Seco (dry code) significa a arquitectura est to bem estruturada que no existe repetio de cdigo. A repetio de cdigo leva a que por vezes um bug seja repetido com a replicao do cdigo, o que torna a sua correco mais difcil, e por vezes corrigido num local e permanece em outro. Ao evitar a repetio de cdigo (princpio DRY), toda a aplicao se torna mais legvel, fcil de gerir e de modificar.
Este tipo de urls permite uma transposio directa da estrutura dos mtodos (pblicos) dos controllers, o que faz com
14
De acordo com o que referido atrs, a Framework Rails utiliza uma filosofia de Convention over Configuration. Por esta razo importante conhecermos algumas das convenes (tambm conhecidas como sensible defaults), de modo a que melhor se possa perceber o comportamento da plataforma.
Existem diferentes tipos de convenes, e seria impossvel abord-las todas aqui. No entanto ficam algumas das mais importantes para a fase de introduo plataforma:
A aplicao que ser construda de seguida, como forma de demonstrao da tecnologia, ser construda apenas com um editor de texto e com a linha de comandos, sem recurso a qualquer IDE, de forma a que possa ser demonstrado, de uma forma mais limpa, o processo de criao. No dia-a-dia, de todo, aconselhvel a utilizao de um IDE, com autocompletion e syntax highlighting.
Base de Dados:
Aptana Studio 3 (grtis) http://www.aptana.com/ RubyMine ( Grtis para projectos OpenSource) - http:// www.jetbrains.com/ruby/
Passemos ento criao da aplicao. O primeiro passo definir o local onde a aplicao ser armazenada. Neste caso a aplicao ir ficar na directoria C:\Sites. De seguida necessrio abrir a linha de comandos. Uma vez dentro da directoria desejada, o comando responsvel pela criao da aplicao o comando: rails new nome_da_aplicacao
Existem bastantes mais convenes. Algumas sero ainda abordadas durante a parte prtica do artigo, que pode ser vista de seguida.
Uma vez executado este comando, sero criados vrios ficheiros e pastas dentro de uma pasta com o nome da aplicao. Neste caso vamos dar o nome lista_de_compras nossa aplicao: rails new lista_de_compras
Aps a execuo deste comando, possvel ver que o script colocou algumas mensagens na consola, indicando a criao dos ficheiros e pastas da aplicao.
Tarefas como criar uma nova aplicao Rails, adicionar uma entidade ao Model, criar um novo Controller, criar um Scaffold (abordado de seguida) ou at iniciar e parar o servidor, implicam o uso da linha de comandos, e implicam tambm o conhecimento de comandos especficos, com uma 15
Vamos ento ver o que cada directoria e ficheiros significam e qual o seu propsito.
Pasta App: aqui que a aplicao reside. Todos os controllers, views, models, helpers residem aqui dentro. Falaremos dela mais frente medida que construmos a aplicao.
Terminada a anlise estrutura da pasta da aplicao, altura de iniciar o servidor e ver pela primeira vez a aplicao a correr. Para tal basta executar o comando: rails server Nota: este comando ter de ser executado dentro da pasta da aplicao, caso contrrio no ser iniciado o servidor.
Pasta Public: Este o local onde so guardadas as imagens, folhas de estilo (CSS) e scripts client-side (Javascript), bem como todas as pginas estticas partilhadas pela aplicao: pgina 404 (not found), etc.
Pasta Script: onde reside o script responsvel pela gerao de itens (views, models, controllers, etc). Este script apenas chama outros scripts/executveis, no sendo ele o verdadeiro responsvel pela gerao/destruio dos elementos.
Pasta tmp: Pasta utilizada pelo Rails para armazenamento temporrio, auxiliar ao processamento.
Como possvel ver, o servidor webBrick iniciado na porta 3000. Se quisermos utilizar a porta padro para um servidor web (porta 80), basta adicionar -p 80 ao comando: rails server p 80
tambm criada uma pasta com o mesmo nome dentro da pasta das Views (App/Views).
Por conveno, todas as views de um controller, devem estar dentro de uma pasta com o nome desse controller (estando esta pasta dentro da pasta views).
Vamos ento gerar o controller Inicio (se o servidor estiver em execuo necessrio par-lo): possvel ver o ambiente da aplicao, clicando na ligao About your applications environment. Aqui podemos conferir a verso dos elementos do nosso ambiente, bem como saber qual dos ambientes est actualmente activo (abordado com maior detalhe mais frente).
Ainda na pgina possvel ver 3 passos para que a aplicao comece a funcionar como deve ser.
1 Criar controllers e models com o comando rails generate 2 Registar rotas 3 Criar e configurar a base de dados
Abrindo a pasta App/Controllers, possvel ver que foi criado um ficheiro chamado inicio_controller.rb, que o ficheiro onde o controller est definido: class InicioController < ApplicationControler end
, agora, altura de definir o que a aplicao vai fazer: ser uma aplicao bastante simples que ir permitir a criao de vrias listas de compras. Cada lista de compras ter um nome e uma prioridade. Uma lista poder ter vrios itens, sendo que cada item ter um nome, um preo estimado e uma quantidade.
O objectivo construir uma aplicao simples que permita a criao, alterao e remoo de listas de compras e dos seus itens. Ir ser utilizado o motor de base de dados SQLite, dado que vem com a instalao da Framework.
Este ficheiro contm uma classe chamada InicioController. Interessa relembrar a naming convention onde no nome dos ficheiros as palavras so separadas por underscore (inicio_controller.rb) e no nome das classes/mdulos utilizado Pascal Case (InicioController).
Esta classe estende (herda de) a classe ApplicationController. Vamos comear pela criao de um Controller chamado Inicio. A criao de controllers faz-se com o comando: Todos os controllers estendem esta classe, e por conveno, o nome utilizado na criao sufixado pela palavra Controller, gerando assim o nome da classe. Como vimos anteriormente, um controller tem mtodos, aos quais podemos chamar de Actions.
17
A View no criada automaticamente, nem existe um script generate para Views. Teremos, por isso, de a criar mo.
Como vimos anteriormente, pelo padro do MVC, conseguimos chegar a uma action utilizando o seguinte url: http:// servidor/controller/action, logo ao abrir o url http://localhost/ inicio/ola devemos chegar a esta Action. Vamos iniciar o servidor e tentar abrir este url no browser.
Vamos ento criar um ficheiro vazio, chamado ola.rhtml, dentro da pasta inicio, que se encontra dentro da pasta views, dentro da pasta app:
Pois , no funciona. O erro diz-nos que no existe ainda nenhuma rota definida que coincida com /inicio/ola. Vamos ento definir a rota standard do MVC: /controller/ action/id. Para isso, vamos at pasta config, dentro da pasta da aplicao, e vamos abrir o ficheiro routes.rb. Vamos alterar o ficheiro de modo a adicionar este mapeamento. Possivelmente a rota est comentada no fim do ficheiro, pelo que basta descomentar (ou adicionar no caso de no existir) a seguinte linha: ListaDeCompras::Application.routes.draw do match ':controller(/:action(/:id))' end Vamos agora abrir o ficheiro no editor de texto e adicionar a seguinte frase: Este texto foi escrito dentro da vista ola do controller inicio.
Depois de guardar o ficheiro, vamos recarregar a pgina que antes estava a mostrar o erro, e dever ser possvel ver o seguinte:
necessrio reiniciar o servidor, de modo a que a nova rota tomada em conta. Abrindo o url anterior, agora o erro diferente: J funciona :) !!
O que aconteceu, que o controller inicio foi encontrado, a action ola tambm foi encontrada, e por conveno, esta Aco tem uma Vista associada com o mesmo nome. Ainda por conveno, a vista estar dentro de uma pasta com o mesmo nome do controller, dentro da pasta das Views 18
Vamos adicionar uma nova rota, de modo a que esta seja a action e controller a ser chamados quando apenas se coloca o endereo base (http://localhost) no browser (Rota de raz ou pr-definida).
Vamos alterar o comportamento da rota de raiz (root) que, por conveno, aponta para o ficheiro index.htm que est na pasta public, e que vimos quando abrimos a aplicao pela primeira vez.
Para que tal acontea vamos, primeiro, apagar ou renomear o ficheiro index.html, que est dentro da pasta public, pois tem precedncia sobre a rota. De seguida vamos modificar ligeiramente o ficheiro de rotas, passando para dentro do bloco de cdigo uma instncia do objecto de gesto de rotas, e vamos adicionar o mapeamento da rota root:
Vamos agora analisar o cdigo fonte que foi gerado para a pgina: <!DOCTYPE html> <html> <head> <title>ListaCompras</title>
<link href="/stylesheets/scaffold.css?1310683055" media="screen" rel="stylesheet" type="text/css" /> <script src="/javascripts/prototype.js?1310683025" type="text/javascript"></script> <script src="/javascripts/effects.js?1310683025" type="text/javascript"></script> <script src="/javascripts/dragdrop.js?1310683025" type="text/javascript"></script> <script src="/javascripts/controls.js?1310683025" type="text/javascript"></script> <script src="/javascripts/rails.js?1310683025" type="text/javascript"></script> <script src="/javascripts/application.js?1310683025" type="text/javascript"></script> <meta name="csrf-param" content="authenticity_token"/> <meta name="csrf-token" content="Wwl+qgnbSIXvi2eRmDY72z1oWAkbzPuKFKIy/tg5W4g="/> </head> <body> Este texto foi escrito pela action ola do controller inicio </body> </html> 19
Como possvel ver, tanto o texto que colocmos no layout como o que est contido na View so mostrados.
Passemos ento anlise do cdigo do template (ficheiro layout.htm.rb). Podemos ver algum cdigo HTML (o mesmo que havamos visto no cdigo fonte da pgina que abrimos pouco no browser) e algum cdigo Ruby (delimitado pelas tags <% %>).
Existem duas formas de inclur Ruby dentro de uma pgina, seja ela um layout ou uma view:
A forma com output <%= instruo %> A forma sem output <% instruo %>
A primeira utilizada para escrever algo na pgina, e a segunda apenas para instrues sem gerao de output. Vamos ento analisar o cdigo Ruby presente nesta pgina:
Por ltimo temos a instruo <%=yield %>. esta instruo que ser substituda pelo contedo da View. Como vimos anteriormente a View aparece com o layout sua volta. , porm, necessrio, indicar qual o local, dentro do layout, onde a view ser mostrada. possvel ter mais do que uma instruo <%= yield %> no mesmo template, sendo que desta forma, a partir do segundo yield (inclusive), estes tero de ter um nome, para poderem ser referenciados de forma distinta. Exemplo de um layout com dois yields: .... html <%= yield barra_topo %> .... html .... <%= yield %>
<%= stylesheet_link_tag :all %> - uma tag Ruby com gerao de output (v-se pelo sinal de igual [ = ] ). Recebe como parmetro o smbolo :all. Este mtodo olha para a pasta stylesheets (dentro da pasta public) e gera cdigo HTML para que as folhas de estilo sejam adicionadas pgina. possvel definir um ficheiro isolado, mas neste caso com o smbolo :all, todas as folhas de estilo contidas na pasta sero carregadas.
<%= javascript_include_tag :defaults %> - um mtodo em tudo semelhante ao anterior, com a diferena de que este no est relacionado com folhas de estilos (CSS) mas sim com ficheiros de script client-side (Javascript) contidos na pasta scripts, dentro da pasta public. O smbolo :defaults passado como parmetro visa carregar alguns ficheiros de javascript, pertencentes Biblioteca Script.acol.us (http:// script.aculo.us/) que vm junto com a aplicao. Existe quem defenda que esta instruo no deveria ser automaticamente adicionada a uma aplicao recm criada, pois implica o carregamento de cerca de 140KB de ficheiros Javascript, e como ficheiros de javascript so carregados em srie, leva a um atraso que pode ser significativo e muitas vezes no se utiliza qualquer javascript.
Para que a sidebar seja preenchida no layout, ter de ser usado mtodo content_for, seguido do nome do yield a que se refere.
Sim. Imagine-se o cenrio tpico de um website com frontoffice e back-office. possvel ter dois (ou mais) layouts e depois, ao nvel do controller ou ao nvel da prpria action definir qual ou template a ser usado, ou ento dizer que no
20
Criao de Modelos No vamos para j gerar o modelo para a lista de compras, pois ir ser utilizada outra tcnica (scaffolding) posteriormente.
Voltando ao objectivo de criar uma aplicao de lista de compras, vamos necessitar de criar o modelo de dados. Imagine -se o seguinte modelo de dados:
Temos que uma lista de compras tem um identificador (id), um nome e uma prioridade, e poder ter vrios itens. Cada item estar ligado a uma lista e ter um campo chave (id), o id da lista a que pertence, um nome e um preo.
Ao observarmos o output do comando que acabmos de invocar, vemos que foram criados 4 ficheiros. Os primeiros dois, aps invocao do active_record (abordado um pouco mais frente) so um ficheiro de migrao, responsvel pela criao da tabela na base de dados e o segundo o ficheiro que contm o Model em si: a classe de Ruby que representa um item da lista de compras.
Este modelo de dados segue as naming conventions de Rails: Utilizar nomes de tabelas no plural, o campo chave em ambas as tabelas chama-se id. A chave estrangeira da list na tabela de itens chama-se list_id: singular da tabela referenciada, seguido de _id. Desta forma, deixamos as convenes fazerem o seu papel, e no necessrio configurar quais as chaves primrias, qual o nome das tabelas, qual o nome das chaves, etc.
altura de criar o modelo de dados na nossa aplicao. A sintaxe semelhante criao de controllers, mas agora existem mais informaes que necessitam de ser passadas no comando: os campos do modelo e os seus tipos de dados. Caso existisse j uma base de dados criada, os campos poderiam ser inferidos a partir da base de dados. No entanto vamos utilizar o paradigma Code First e vamos deixar que seja o Rails a criar a base de dados por ns.
Os outros dois ficheiros, criados aps invocao do unit_test, dizem respeito aos testes unitrios para a entidade item. aqui que sero especificados os testes unitrios (no sero abordados neste artigo). Interessa notar quem um dos ficheiros um ficheiro Ruby (extenso .rb) e o outro um ficheiro YAML (extenso .yml). Este tipo de ficheiros ser abordado aquando da configurao da base de dados.~
Scaffolding
A sintaxe para gerao de uma entidade de model : rails generate Model nome_do_modelo [parametros]
O conceito de Scaffold (esqueleto), neste contexto, significa a construo de um back-end, dentro de uma aplicao informtica, a partir dos dados e meta-dados contidos na base de dados. A partir da anlise da estrutura da base de dados, gera cdigo e interface para as operaes CRUD (Create, Read, Update, Delete).
A passagem de parmetros facultativa. Se no forem passados parmetros, os atributos da classe gerada sero inferi21
Em Rails, o scaffolding apresenta-se como uma mais-valia da tecnologia. Se por um lado o resultado nem sempre o esperado, e em muitas das vezes existem vantagens em fazer manualmente a interface e cdigo para as operaes
Vamos utilizar scaffolding para gerar uma interface para gerir as listas de compras. A gesto dos itens de cada lista ser feita do modo tradicional, ou seja, criando tudo mo.
Falta apenas tratarmos da relao entre estes dois elementos do Model para que o modelo de dados esteja definido por completo. Para isso necessrio dizer que uma lista pode ter vrios itens, e que um item pertence a uma lista. Parece simples dizer isto desta forma, e de facto simples colocar esta lgica no cdigo. Abrindo o ficheiro list.rb que se encontra dentro da pasta model, vamos ento indicar que uma lista pode ter vrios itens: class List < ActiveRecord::Base
A sintaxe da criao de um scaffold semelhante da criao do model. A criao de um scaffold agrega a criao de uma entidade do Model, e a criao de um controller e das actions e views necessrias para que tudo funcione (da no ter sido criado o Model list anteriormente).
has_many :itens
Como possvel ver, esta no uma classe normal. uma classe que deriva (herda) da classe Active Record - Base. Como tal contm alguns mtodos especiais, como o caso deste has_many. Este mtodo recebe um smbolo como parmetro, e o smbolo (no plural neste caso) indica qual a entidade presente na relao.
Da mesma forma, no ficheiro item.rb vamos dizer que um item pertence a uma lista: class Item < ActiveRecord::Base importante observar, no output do comando, que o scaffold no faz nada por si s. O que faz invocar o active_record, o scaffold_controller e o gerador de stylesheets para que o todo o scaffold possa ser criado. belongs_to :list end
Note-se, ainda, que foi criado um controller chamado lists e vrias Views para este controller (index, edit, show, new e _form). Iremos voltar ao controller e s views mais frente.
O mtodo belongs_to indica que um item pertence a uma lista (repare-se que o smbolo neste caso est no singular).
A partir da verso 2.0 do rails, deixou de ser possvel gerar um scaffold para uma entidade j existente, sendo a entidade criada ao mesmo tempo que o scaffolding. por isso necessrio pensar bem se uma determinada entidade vai ser usada com scaffolding ou no.
Tendo o modelo de dados definido, altura de fazer reflectir estas alteraes na base de dados. Mas qual base de dados? Existe um ficheiro chamado database.yml dentro da pasta config. Este ficheiro utiliza um formato chamado YAML (YAML aint markup language).
O Rails encarrega-se de adicionar um recurso s rotas, de modo a que as ligaes usadas pelo scaffold para navegao, funcionem: map.resources :lists
um formato de serializao como o XML e JSON que no caso do Rails muito utilizado para configuraes. Basicamente, em YAML, um elemento definido pelo seu nome seguido de dois pontos ( : ). Depois os campos/atributos deste elemento so precedidos por um espaamento (tab) e o valor de cada campo precedido de dois pontos ( : ).
22
Antes de procedermos migrao, vamos ver os ficheiros de migrao que foram gerados. Estes ficheiros (um por cada entidade) devero estar na pasta db/migrate. Vamos abrir o ficheiro de migrao para a entidade Item.
O ambiente predefinido, e que nos interessa neste caso, o ambiente de desenvolvimento. possvel mais tarde alterar o ambiente de funcionamento (para produo, por exemplo). Podemos ver que est a ser utilizado o motor de base de dados sqlite3, e que a base de dados ir residir dentro da pasta db e que se ir chamar development.sqlite3. Est tambm definido o nmero mximo de ligaes e o tempo mximo de espera.
Caso o motor de base de dados fosse diferente (por exemplo MySQL) os campos da parametrizao seriam outros (host, 23
tambm importante referir que foram adicionados dois campos a cada tabela: updated_at e created_at. Estes so dois campos do tipo datetime e automagicamente (graas ao active_record) guardam a data/ hora de criao ou alterao do objecto.
Estando o modelo de dados reflectido na base de dados, podemos iniciar o servidor e tentar abrir o scaffold da lista, atravs do controller lista que foi criado.
Vamos aceder ao seguinte url: http://localhost/lists, que nos d acesso a uma tabela com as listas j existentes (inicialmente vazia) e uma ligao para o formulrio que permite criar novas listas.
Todo o cdigo gerado est disponvel para consulta e alterao, tanto ao nvel do controller como ao nvel das Views, e uma boa forma de perceber como o Rails funciona.
Vamos agora fazer o mesmo processo para os itens, mas sem usar scaffolding. Por questes de brevidade iro apenas ser demonstrados a criao e listagem de itens.
O primeiro passo ser gerar o controller para os itens. Este controller ir conter as actions (e Views) para listar, criar, alterar e apagar itens de uma determinada lista.
Vamos adicionar uma action chamada new. Esta action e a respectiva view tero como responsabilidade permitir a criao de um novo item. tambm necessrio criar o ficheiro da View, dado que no criado automaticamente.
tambm definida uma varivel global chamada lists. A classe List, estende a classe ActiveRecord, pelo que contm uma srie de mtodos relacionados com o acesso a dados.
Passemos ento anlise do cdigo da View para a construo do formulrio. Como possvel ver, para aceder varivel com o ttulo, basta invoc-la, sem esquecer da arroba antes do nome da varivel. O Rails proporciona tambm Helpers para a construo do formulrio. Ainda que este possa ser construdo com HTML, a utilizao dos Helpers ajuda a reduzir o cdigo e a torn-lo mais fcil de ler.
O ActiveRecord uma ferramenta ORM, e como tal permite que o developer se concentre no desenvolvimento, abstraindo de uma forma completa a base de dados. No sequer necessrio escrever SQL, dado que atravs dos mtodos disponveis, o ActiveRecord encarrega-se de gerar o SQL necessrio.
A instruo form_tag, recebe a aco, que neste caso est direccionada para a Action Create. Quando se omite o Controller, assume-se que a aco pertence ao controller actual. Esta instruo termina com o end, no final da pgina e considera-se que tudo o que estiver entre estas duas instrues est dentro do formulrio. Basicamente traduzem-se nas tags <form ..> e </form> do HTML, respectivamente. Os Helpers no se limitam criao do formulrio, mas tambm na criao dos campos deste. A sintaxe do Helper para criao de inputs de texto a seguinte: text_field :nome_objecto, :nome_do_campo
Um desses mtodos o find. Este mtodo recebe como parmetros elementos como condies de pesquisa, o nmero de elementos e o offset (para paginao), e devolve um Array com elementos, trazidos directamente da base de dados. Vamos ver mais alguns mtodos do ActiveRecord mais frente, medida que vai sendo necessrio utiliz-los.
Abrindo a janela da consola, onde o servidor est a ser executado, possvel ver o cdigo SQL gerado.
Por exemplo, para criar uma caixa de texto, para o campo name de um objecto chamado item utiliza-se a instruo text_field :name, :item
<h3><%= @title %></h3> <%= form_for :item, @item, :url => { :action => "update" ,:id=>@item.id} do | f | %> Id:</br> <%= f.text_field :id,:disabled => true %> <br/> Nome:<br/>
A criao de um Select (ou uma caixa de seleco) tambm beneficia de um Helper. Na action que invoca esta View, crimos uma varivel global chamada @lists, onde passmos, atravs do mtodo find do ActiveRecord, todas as listas da base de dados.
25
Esta instruo serializa (em formato YAML) o objecto ou a coleco de objectos. Neste caso, existem duas listas na base de dados e o resultado este:
--- !ruby/object:List attributes: name: Supermercado created_at: 2011-07-14 22:46:05.199146 updated_at: 2011-07-14 22:46:05.199146 id: 1 prioridade: 1 attributes_cache: {} changed_attributes: {} destroyed: false marked_for_destruction: false new_record: false previously_changed: {} readonly: false - !ruby/object:List attributes: name: "M\xC3\xBAsica" created_at: 2011-07-14 22:46:34.065217 updated_at: 2011-07-14 22:46:34.065217 id: 2 prioridade: 3 attributes_cache: {} changed_attributes: {} destroyed: false marked_for_destruction: false new_record: false previously_changed: {} readonly: false
Por ltimo existe um Helper para o boto de Submit submit_tag que recebe o valor a apresentar no boto.
Vamos analisar o cdigo HTML gerado pelos helpers. <form accept-charset="UTF-8" action="/itens/create" method="post"> <div style="margin:0;padding:0;display:inline"> <input name="utf8" type="hidden" value="✓"/> <input name="authenticity_token" type="hidden" value="Wwl+qgnbSIXvi2eRmDY72z1oWAkbzPuKFKIy/ tg5W4g="/> </div> Nome:<br/> <input id="item_name" name="item[name]" size="30" type="text" /> <br/>
Este o resultado da serializao, com o mtodo debug. Este mtodo torna-se especialmente til quando algo corre mal e no se sabe muito bem de onde vem o problema.
Interessa reter que cada elemento da lista tem um campo id, e um campo name, que sero utilizados na caixa de seleco. Podemos agora retirar a instruo de debug e descomentar o restante cdigo.
26
A segunda linha chama o mtodo save (herdado do ActiveRecord) e o objecto automaticamente persistido na base de dados.
tambm possvel ver que foi criado um campo escondido chamado autenticity_token que serve para que a autenticidade do request possa ser comprovada pelo Rails. Este token comparado com o token que figura na seco <HEAD> da pgina e que falmos anteriormente (CSRF).
Da mesma forma que anteriormente, utiliza-se o ActiveRecord para trazer todos os itens, mas desta vez, ordenados pelo campo list_id.
View Index (ficheiro itens/index.rhtml): ainda possvel ver que o nome de todos os campos segue um padro: nome_do_objecto[nome_do_campo]. Este padro tem uma razo de ser, pois facilita muito a criao do objecto Ruby a partir dos valores do formulrio, como veremos de seguida. <h3><%= @title %></h3> <table border="1"> <tr> <th>Nome</th> <th>Preo</th> <th>Lista</th> <th></th> </tr> <% @itens.each do |item| %> <tr> <td> <%= item.name%> </td> <td> <%= item.price%> </td> <td> <%= item.list.name%> </td> <td> <a href="/itens/edit/<%=item.id%>">Editar</a> <a href="/itens/destroy/<%=item.id%>">Eliminar</a> </td> </tr> <%end%> </table> <a href="/itens/new">Novo Item </a>
Passemos ento criao da Action responsvel pela recolha dos dados passados pelo formulrio e pelo registo do item na base de dados. Falamos da Action Create do Controller Itens. def create @item = Item.new(params[:item]) @item.save redirect_to(:action=>'index') end Estas 3 linhas de cdigo so suficientes para pegar nos dados do formulrio e guardar o objecto na base de dados. De facto, as primeiras duas linhas bastam. A terceira linha apenas redirecciona o browser para View Index, que ir, dentro de alguns momentos, conter a listagem de todos os itens, presentes em todas as listas de compras.
A instruo presente primeira linha do mtodo obtm a partir dos valores passados pelo formulrio (neste caso via POST)
27
Concluso Nota: Esto tambm a ser criados dois links para a alterao e destruio dos itens. Apesar de estes duas componentes da aplicao, por questes de brevidade, no serem abordadas no artigo, esto contidas no cdigo da aplicao, cujo link para download est no final do artigo. Por agora tudo. Apesar de ter sido um exemplo simples, espero ter demonstrado como o Ruby on Rails funciona e, pelo menos, ter despertado o vosso interesse para esta tecnologia. O que foi abordado aqui foi apenas uma muito pequena parte desta vasta e rica tecnologia de desenvolvimento web.
Para quem quiser aprofundar mais, deixo um conjunto de links que sero certamente muito interessantes.
Webcasts sobre Rails: http://railscasts.com/ Site Oficial Ruby (PT): http://www.ruby-lang.org/pt/ Site Oficial Rails: http://rubyonrails.org/ Documentao Ruby: http://www.ruby-doc.org/ Documentao API Rails: http://api.rubyonrails.org/ Comunidade Ruby-pt: http://www.ruby-pt.org/ Alojamento Rails (gratuito no pacote mais bsico): http:// www.heroku.com/ Livro: Whys (poignant) guide to Ruby: http:// www.rubyinside.com/media/poignant-guide.pdf
Escrito por Carlos Rodrigues Licenciado em Engenharia Informtica pelo Instituto Politcnico de Viseu, frequenta actualmente o Mestrado em Sistemas e Tecnologias de Informao para Organizaes na Escola Superior de Tecnologia de Viseu. actualmente consultor / programador na rea da banca, por uma multinacional Portuguesa na regio de Lisboa e formador em regime de freelance. Interessa-se pelo desenvolvimento para web e para dispositivos mveis. Twitter: @crodriguesPT Blog: http://crodrigues.com
28
Neste artigo so apresentadas informaes introdutrias e bsicas sobre o uso da linguagem Lua embutida dentro de programas escritos em C e C++. Alm deste tema apresenta -se tambm informaes relacionadas ao uso de co-rotinas. Para a execuo dos programas codificados nas linguagens C e C++ integrados com a linguagem Lua deve-se levar em considerao o uso do compilador GCC.
Lua Embutida
Lua foi concebida para comunicar-se com a linguagem C, ou seja, foi preparada para ser uma biblioteca da linguagem C. No entanto, permite ser usada como linguagem independente como apresentado nas nove partes anteriores desta srie de artigos.
Linguagem de Script
Em 12 de Maio de 2011 foi publicado na revista ACM Queue Architecting Tomorrow's Computing o artigo intitulado Passing a Language through the Eye of a Needle (Passando uma Linguagem atravs do Buraco de uma Agulha), onde Roberto Ierusalimschy, Luiz Henrique de Figueiredo e Waldemar Celes arquitectos da linguagem Lua falam sobre o uso da linguagem Lua com outras linguagens.
Usar a integrao de Lua com C++ foi uma ocorrncia natural, devido origem de C++ a partir de C. No caso de uso das linguagens C e C++, o uso de Lua semelhante entre elas. Assim sendo, necessrio fazer uso dos arquivos de cabealho lua.h, lauxlib.h e lualib.h; integrantes da biblioteca Lua, de-nominadas API C, a qual escrita em ANSI C. As funes do arquivo lua.h so iniciadas pelo prefixo lua_, as funes do arquivo auxiliar lauxlib.h so iniciadas pelo prefixo _luaL e o arquivo lualib.h d acesso s bibliotecas padro da linguagem Lua. A identificao do uso das bibliotecas de API C em linguagem C utilizada com a chamada dos arquivos de cabealho que so configuradas dentro da funo main a partir da definio em negrito indicado a seguir:
#include <stdio.h>
Em http://www.lua.org/portugues.html, se l que Lua uma engine rpida e pequena que voc pode facilmente embutir na sua aplicao. Lua tem uma API simples e bem documentada que permite uma integrao forte com cdigo escrito em outras linguagens. simples estender Lua com bibliotecas escritas em outras linguagens. Tambm simples estender programas escritos em outras linguagens com Lua. Lua usada para estender programas escritos no s em C e C++, mas tambm em Java, C#, Smalltalk, Fortran, Ada, Erlang, e mesmo outras linguagens de script, como Perl and Ruby. Dentro da temtica desta discusso que este artigo mostra como fazer a integrao de cdigo em linguagem Lua (linguagem de script) de forma embutida em cdigos previamente escritos em C e C++.
#include <lua.h> #include <lauxlib.h> #include <lualib.h> int main(void) { // cdigo com funes Lua
return 0; }
A linguagem de programao Lua possui duas importantes caractersticas, pode ser usada como linguagem de extenso e como linguagem extensvel, ou seja, o fluxo de comunicao com a linguagem Lua bidireccional. Como linguagem de extenso, Lua pode ser usada juntamente com outra linguagem no sentido de estender alguma funcionalidade embutida para esta outra linguagem. Como linguagem extensvel, Lua pode ser usada para obter uso de recursos existentes em outra linguagem, a fim de se completar. A comunicao entre as linguagens C, C++ e Lua pode ocorrer sob duas esferas: na primeira esfera por meio da definio de uma instncia de estado de operao e na segunda esfera por meio do uso do conceito de pilha. O foco de estudo deste artigo concentra-se na primeira esfera.
A identificao do uso das bibliotecas de API C em linguagem C++ utilizada com a definio do bloco externo com a clusula extern a partir da definio em negrito indicado a seguir: #include <iostream> extern "C" { #include <lua.h> #include <lualib.h> #include <lauxlib.h> } using namespace std; int main(void) { // cdigo com funes Lua return 0; }
30
A primeira definio a ser configurada na funo main() a indicao de uma varivel ponteiro que dar acesso instncia da operao Lua, representado pelo ponteiro do tipo lua_State *. Aps a definio da instncia de estado para um ponteiro do tipo lua_State * torna-se necessrio criar pelo menos um estado de uso para este ponteiro com a funo lua_open().
O valor retornado pela funo lua_open() o ponteiro lua_State * necessita de ser passado como argumento (parmetro) s demais funes da API C que venha a ser utilizado dentro do cdigo do programa. Todo o estado da operao Lua definido dentro da funo main() necessita de ser encerrado com o uso da funo lua_close(). Assim sendo, note o trecho em negrito da funo main() seguinte: int main(void) { lua_State *ACESSO = lua_open(); // acesso as funes Lua lua_close(ACESSO); return 0; }
O compilador GCC uma ferramenta de trabalho similar ferramenta CC do UNIX, a qual opera em vrios sistemas operativos. Possui como forma de uso, uma certa diversidade na sua escrita, tal como pode ser observado junto a vrios sistemas operativos: S.O. UNIX Linux Linux Comando cc o exec exemplo1.c gcc o exemplo1.c exec g++ -o exemplo1.c exec gcc exemplo1.c o exec g++ exemplo1.c o exec gpp exemplo1.c -o exec
Note que a instncia de acesso ao estado Lua definido pelo ponteiro (varivel de estado) ACESSO, inicializada com a funo lua_open() e finalizada com a funo lua_close() antes do uso da instruo return 0;. // Exemplo 1 #include <stdio.h> #include <lua.h> #include <lauxlib.h> #include <lualib.h> int main(void) { lua_State *ACESSO = lua_open(); luaL_openlibs(ACESSO); luaL_dostring(ACESSO, "print('Ola.')"); lua_close(ACESSO); return 0; } O programa seguinte apresenta um programa escrito em linguagem C, o qual executa uma instruo em linguagem Lua. O mesmo bloco de cdigo main() poderia estar sendo definido dentro de um programa C++. 31
No entanto, comum encontrar certas variaes no uso da sintaxe de escrita do comando de compilao para o GCC. H situaes onde necessrio acrescentar junto linha de compilao as flags -llua llualib ou as flags llua5.1 llualib5.1, ou uma variao entre elas.H situaes onde necessrio indicar os locais onde se encontram as bibliotecas o que implica o uso de um complemento da linha de compilao com as opes I indicando o uso do directrio include e L indicando o uso do directrio lib do local onde se encontra a instalao da linguagem Lua. Dependendo do sistema operativo em uso e da forma de instalao da linguagem Lua necessrio acrescentar junto a linha de compilao a opo -Wall lua-config --include -libs.
Co-Rotinas
Co-rotina o nome dado a uma actividade operacional que permite a uma sub-rotina de programa, quer seja um procedimento ou uma funo, ser suspenso temporariamente em determinado ponto de execuo e venha a ser executada noutro momento. Este tipo de aco tambm conhecido como fluxo de execuo colaborativo (threads).
No caso da linguagem Lua, a execuo de co-rotinas ocorrer por meio de uma linha de execuo independente que faz uso de uma pilha prpria de chamadas. Para fazer uso deste recurso Lua possui uma biblioteca (mdulo) chamado coroutine, a qual disponibiliza para uso algumas funes operacionais, tais como: coroutine.create(); coroutine.status(); coroutine.resume();coroutine.wrap();coroutine.yield ().
O funcionamento de co-rotinas na linguagem Lua difere do modo encontrado em sistemas convencionais multithreading (multitarefas), pois no efectua qualquer aco que cause a mudana de processamento. Em Lua uma co-rotina s pode ser interrompida quando esta termina ou quando para ela chamado explicitamente uma aco de suspenso de execuo por intermdio da funo yield().
// Exemplo 2 #include <stdio.h> #include <lua.h> #include <lauxlib.h> #include <lualib.h> int main(void) { lua_State *ACESSO = lua_open(); luaL_openlibs(ACESSO); luaL_dofile(ACESSO, "teste.lua"); lua_close(ACESSO); return 0; } Grave o programa com o nome exemplo2.c. Note o uso da funo luaL_dofile() que carrega e executa o contedo do arquivo indicado, neste caso o arquivo teste.lua que possui a capacidade de apresentar os valores pares situados na faixa de 2 a 20.
Para a criao de co-rotinas pode-se usar as funes create () ou wrap(). A funo create() cria uma nova co-rotina mas no a coloca em execuo, deixando-a em modo de suspenso e para ser executada necessita da execuo da funo resume(). J a funo wrap() cria uma co-rotina que possui como caracterstica a capacidade de ser recomeada automaticamente sempre que a co-rotina chamada.A funo yield() como comentado suspende a execuo de uma corotina de forma temporria. A funo status() detecta o estado operacional de uma co-rotina que pode ser:
normal (quando uma co-rotina retorna seu fluxo de execuo a outra co-rotina);
32
Ao ser executado o programa ocorrer a apresentao da mensagem suspended e ocorrer tambm a apresentao da mensagem de erro. Em seguida a cada vez que executada a funo resume() ocorre a chamada da co-rotina e um valor da varivel I do lao apresentado, pois a cada vez que chamada a co-rotina a funo yield() faz a interrupo da co-rotina. O programa a seguir faz uso da co-rotina criada com a funo wrap(). Observe o cdigo sugerido. -- incio do programa CO-ROTINA4 rotina = coroutine.wrap( function (N) R = N print(R) coroutine.yield() R = N * 2 print(R) end ) N = 2 rotina(N) rotina(N) -- fim do programa CO-ROTINA4
O prximo exemplo de programa faz uso da funo yield(). Observe o cdigo seguinte: -- incio do programa CO-ROTINA2 rotina = coroutine.create( function () for I = 10, 16, 2 do print(">> " .. I) coroutine.yield() end end ) print(coroutine.status(rotina)) print(rotina) coroutine.resume(rotina) print(coroutine.status(rotina)) coroutine.resume(rotina) print(coroutine.status(rotina)) coroutine.resume(rotina) print(coroutine.status(rotina)) coroutine.resume(rotina) print(coroutine.status(rotina)) -- fim do programa CO-ROTINA2
Em seguida escreva o cdigo de programa num editor de texto, gravando-o com o nome corotina3.lua e execute-o com a linha de comando lua 5.1 corotina3.lua. O programa ao ser executado apresenta os valores 2 e 4. Note que neste exemplo a funo wrap() possui sua funcionalidade semelhante funo create().
J no prximo programa a co-rotina criada com a funo wrap() interrompida com o uso da funo yield(). A funo resume() usada para iniciar a execuo de uma co-rotina criada por meio da funo create(). Para efectuar um teste de uso de co-rotinas considere um programa que apresente a mensagem Ol, Mundo!, como segue.
33
Concluso
Ao longo deste tempo, desde o nmero 21 da revista PROGRAMAR, foi fornecido aos leitores um mini-curso introdutrio e bsico de conhecimento da linguagem de programao Lua, para os falantes do idioma portugus. H muita gente que utiliza esta linguagem, mas parece existir poucas pessoas com disposio a compartilhar as suas experincias e conhecimentos. Muitos dos tutoriais, disponveis e encontrados na internet no atendem plenamente s necessidades dos leitores, mas so um bom comeo.
bvio tambm que esta srie de artigos sobre a linguagem Lua no perfeita e nem se teve este intuito, seria muita heresia da nossa parte. Como material inicial esta srie um comeo, e assim deve ser tratada pelos nossos amigos leitores. H muito que percorrer. H muito o que fazer para se popularizar o conhecimento, no s das tecnologias da informtica, mas de diversas reas do saber humano.
Este , temporariamente, um ltimo artigo desta srie. Diz-se temporariamente, pois h muito a dizer em relao linguagem Lua. No entanto, tambm muito foi dito nestes dez artigos ao longo dos ltimos meses. Assim, a qualquer instante poder-se- apresentar novos complementos de estudo e com certeza ter-se- outras partes, como 11, 12, 13 e sabese l, quantas mais. A diferena entre os prximos artigos sobre Lua e a srie que aqui se encerra, que nos dez captulos que se completam com este foi feito um mini-curso para novatos em programao Lua, e os prximos artigos abordaro temticas direccionadas a um pblico que a partir deste artigo j possui algum conhecimento desta linguagem.
Escrito por Augusto Manzano Natural da Cidade de So Paulo, tem experincia em ensino e desenvolvimento de programao de software desde 1 986. professor da rede federal de ensino no Brasil, no Instituto Federal de Educao, Cincia e Tecnologia. tambm autor, possuindo na sua carreira vrias obras publicadas na rea da computao.
34
Introduo Quem j utilizou as facilidades RSS do SharePoint certamente j se deparou com alguns problemas de configurao ao nvel do output da informao que sai com RSS Standard, como por exemplo a designao dos campos e os longos caminhos que temos de utilizar do tipo: _layouts/listfeed.aspx?List=ab4a2784-8309-4905-88be71449afcd9a3&View=6db1464a-f5a1-43de-9526dc94b064052e Neste artigo vamos abordar uma forma simples e eficaz de atravs de RSS 2.0 fazer um Response directamente numa pgina ASPX com um Controlo de Utilizador Estrutura XML RSS 2.0
Consideraes Iniciais
A primeira considerao que temos de ter em ateno que para efectuarmos o nosso response no podemos utilizar nenhum Layout de Pgina, temos de utilizar uma pgina que saia do SharePoint como acontece em todos os procedimentos deste tipo.
<?xml version="1.0" encoding="UTF-8" ?> <rss version="2.0"> <channel> <title>RSS Title</title> <description>This is an example of an RSS feed</description> <link>http://www.someexamplerssdomain.com/ main.html</link> <lastBuildDate>Mon, 06 Sep 2010 00:01:00 +0000 </lastBuildDate> <pubDate>Mon, 06 Sep 2009 16:45:00 +0000 </ pubDate> <item> <title>Example entry</title> <description> Here is some text containing an interesting description. </description> <link>http://www.wikipedia.org/</link> <guid>unique string per item</guid> <pubDate>Mon, 06 Sep 2009 16:45:00 +0000 </ pubDate> </item> </channel> </rss>
Neste exemplo vamos utiliza uma pgina ASPX e vamos adicionar um Controlo de Utilizador mesma, visto a grande maioria das Aplicaes SharePoint assentar em camadas, uma delas certamente a de estrutura do nosso site onde colocamos todas as nossas pginas ASPX, Controlos de Utilizador, Layouts e finalmente as nossas Features por forma a propagarmos a nossa estrutura na altura da Instalao do Portal activando-as.
Vamos separar o nosso CAML Query do mtodo principal por forma a termos uma maior percepo do cdigo.
protected SPQuery ONossoCamlQuery() { SPQuery qry = new SPQuery(); qry.ViewAttributes += "Scope=\"Recursive\""; string camlQry = String.Empty; qry.Query = camlQry; O prximo passo, a nossa String para a Query. Neste passo temos de modificar OSeuCampoData para o nome do campo que queremos filtrar, em que sugiro a utilizao do CAML QUERY BUILDER (http://www.u2u.be/res/Tools/CamlQueryBuilder.aspx). Dever funcionar em ambos MOSS e SharePoint 2010, pelo menos para elaborarmos o nosso filtro.
Fonte: http://en.wikipedia.org/wiki/Rss
O mtodo consiste em criarmos uma Response e dinamicamente renderizar o XML Standard enumerando uma Lista de Pginas de SharePoint filtrado pelo nosso CAML Query readonly string NossoUrlNivelRoot = String.Format("{0}//{1}:{2}", SPContext.Current.Site.Protocol, SPContext.Current.Site.HostName, SPContext.Current.Site.Port);
Vamos buscar o URL de Root dinamicamente: Dentro do URL de Root vamos buscar a rea onde est a lista de pginas, exemplo Noticias string URL = NossoUrlNivelRoot + "/
O mtodo completo: protected SPQuery ONossoCamlQuery() { SPQuery qry = new SPQuery(); qry.ViewAttributes += "Scope=\"Recursive\""; string camlQry = String.Empty; qry.Query = camlQry; try { camlQry = "<OrderBy><FieldRef Name='OSeuCampoData' Ascending='False' / ></OrderBy>"; qry.Query = camlQry; } catch (Exception) { throw; } qry.RowLimit = 10; return qry; } Limpamos a nossa Response e iniciamos uma nova baseada em XML.
Definir o encoding para UTF8 e comear a escrever o XML na pgina. XmlTextWriter TextWriter = new XmlTextWriter (Response.OutputStream, Encoding.UTF8); TextWriter.WriteStartDocument(); TAGS mandatrias RSS 2.0 TextWriter.WriteStartElement("rss"); TextWriter.WriteAttributeString("version", "2.0"); O Channel TAG que vai conter a informao do FEED criando o nosso n XML channel, dentro deste iremos criar a seguir outro n chamado item com a informao das nossas pginas SharePoint.
Primeiro vamos definir no ASPX do nosso controlo a durao do Cache de Sada, que ser a durao permitida do OutputCache por forma a no ficarmos com pedidos longos. Mais informao em (ASP.NET Caching) http://msdn.microsoft.com/pt-br/library/xsbfdd8c.aspx
TextWriter.WriteStartElement("channel"); TextWriter.WriteElementString("title", "JOAO TITO LIVIO"); TextWriter.WriteElementString("link", "http://msmvps.com/blogs/officept/default.aspx"); TextWriter.WriteElementString("description", "Espero que gostem deste RSS"); 37
Vamos fechar todos os elementos e acabar a nossa Response. TextWriter.WriteEndElement(); TextWriter.WriteEndElement(); TextWriter.WriteEndDocument(); TextWriter.Flush(); TextWriter.Close(); Response.End();
Escrito por Joo Tito Lvio MCP e MCTS em SharePoint 2010 Development, neste momento trabalha como Consultor e Programador na CIL Centro de Informtica, SA. Microsoft Most Valuable Professional (MVP) na categoria de Office Systems Development desde 2002
39
Objective C
O Objective-C uma linguagem dinmica baseada nas linguagens C e Smalltalk, uma procedimental e outra orientada a objectos. Na realidade o Objective-C no nada mais do que a linguagem C com esterides, adicionando potncia da linguagem C o sistema de mensagens do Smalltalk.
Sintaxe
Em Objective-C as classes so compostas por duas componentes distintas, interface e implementao. Encontram-se divididas em ficheiros onde a extenso que indica o seu propsito, quando se trata de um ficheiro com a extenso .h trata-se da declarao do interface da classe e quando o ficheiro tem como extenso .m trata-se da implementao da classe. Na figura 1, apresentada em baixo, est definido o interface da classe Cliente. No caso de o leitor ter experincia nas linguagens orientadas a objectos mais comuns, como Java ou C#, natural que cause alguma estranheza e at confuso a sintaxe do Objective-C, no entanto essa sensao ultrapassada rapidamente depois de compreendidos os conceitos bsicos da linguagem.
Como a linguagem C parte integrante do Objective-C, grande parte da sintaxe comum entre estas duas linguagens.
Os tipos primitivos, declarao de funes e chamada de funes da linguagem C so exactamente iguais em Objective-C e, por outro lado, todas as funcionalidades que so orientadas a objectos implementam o sistema de mensagens do Smalltalk. O leitor tem at a liberdade de integrar cdigo desenvolvido na linguagem C/C++ no seu programa de Objective-C e utiliza-lo sem qualquer tipo constrangimento.
iOS
o sistema operativo proprietrio da Apple utilizado nos seus dispositivos mveis, como o iPhone e o iPad. O seu principal trunfo o user interface, que permite uma utilizao natural e agradvel graas utilizao de gestos e aces multi-toque como meio de interaco com o dispositivo. O iOS encontra-se divido em quatro camadas: Core OS, Core Services, Media Layer e Cocoa Touch. Para facilitar o desenvolvimento de aplicaes para iOS, a Apple disponibiliza a iOS SDK, um kit de desenvolvimento, que apenas possvel instalar em computadores Apple Macintosh, e contm todas as ferramentas necessrias para desenvolver aplicaes para a o iOS. Figura 1- Interface da classe Cliente
A interface o local apropriado para definir as propriedades e funcionalidades de uma classe em Objective-C.
CocoaTouch
uma das principais camadas do iOS, disponibiliza o acesso a um conjunto de APIs que facilitam o desenvolvimento de aplicaes e permite a utilizao de algumas funcionalidades chave do iOS, como a cmara fotogrfica, GPS, udio e vdeo.
Na acima apresentada, o leitor pode identificar alguns dos elementos principais de uma classe como variveis, propriedades, mtodos e herana. Existem algumas particularidades que so essenciais esclarecer nesta fase:
41
O Objective-C encarrega o programador das tarefas de gesto de memria, logo sempre que se cria uma instncia de uma classe, necessrio alocar e inicializar espao de memria para o objecto que instanciado, bem como se torna necessrio proceder sua libertao o objecto no mais necessrio. Cliente *cli = [[Cliente alloc] init]; cli.clienteID = 20; cli.morada=@"1 Infinite Loop Cupertino, CA 95014"; cli.nome =@"Apple Computer, Inc."; Factura *fact = [[Factura alloc] init]; fact.facturaID = @"NSOF556323"; Cheque *cq = [[Cheque alloc] init]; cq.numero = @"AB65656135454656265"; [cli pagar:fact]; [cli pagar:fact comCheque:cq];
Na assinatura de um mtodo, os parmetros so definidos atravs da seguinte sintaxe: palavraChave: tipoDoParametro nomeDoParametro #import "Cliente.h" @implementation Cliente @synthesize nome; @synthesize morada; @synthesize clienteID;
-(void)pagar:(Factura *)factura{ NSLog(@"O cliente %@ vai pagar factura n %@", nome, factura.facturaID); } -(void)pagar:(Factura *)factura comCheque:(Cheque*) cheque{ NSLog(@"O cliente %@ vai pagar factura n %@ com o cheque n %@", nome, factura.facturaID, cheque.numero); } +(Cliente*)criarInstanciaComNome:(NSString*)nome comMorada:(NSString*)morada comID:(int) clienteID{ Cliente *cli = [[Cliente alloc] init]; cli.clienteID = clienteID; cli.morada=morada; cli.nome =nome; return [cli autorelease]; } @end Figura 2- Implementao da classe Cliente no ficheiro de implementao que, como o prprio nome refere, implementado tudo o que foi definido no ficheiro de interface da classe Cliente. importante lembrar que necessrio fazer referncia ao ficheiro onde est declarado o interface da classe. necessrio definir atravs da palavra-chave @synthetize, as propriedades no ficheiro de implementao para que o compilador gere de forma automtica os assessores das propriedades.
destruio
de
Na figura 3, o leitor pode observar como se instncia um objecto, atribui valores s suas propriedades, executa um mtodo e, quando o propsito do objecto foi cumprido, se procede sua destruio. Em Objective-C, os objectos so criados com a sintaxe Classe *apontador = [[Classe alloc]init]; os mtodos so executados com a atravs de [objecto nomeDoMetodo]; e os objectos so libertados quando se executa o mtodo [objecto release]; Assim sendo, o resultado da execuo do cdigo da figura 3, com base na implementao executada na figura 2 e definida na figura 1 o seguinte: O cliente Apple Computer, Inc. vai pagar factura n NSOF556323 O cliente Apple Computer, Inc. vai pagar factura n NSOF556323 com o cheque n AB65656135454656265
Tap Counter
Depois de o leitor instalar o iOS SDK, tem sua disposio um conjunto de ferramentas que lhe permite desenvolver aplicaes para iOS. Entre as ferramentas includas no iOS SDK est o XCode IDE e o iOS Simulator. O Tap Counter uma aplicao cujo nico objectivo manter um contador do nmero que vezes que o utilizador pressiona um boto.
42
Execute o XCode4 IDE e crie um novo projecto do tipo View -based Application como exemplificado na figura 4 e atribua o nome PT_AT_PROG ao projecto.
Figura 7 Implementao da interface definida No ficheiro de implementao, o leitor apenas necessita de inicializar a varivel count e implementar o evento buttonTouchDown. Agora que o leitor tem concludo o cdigo em Objective-C necessrio necessrio desenvolver um User Interface que permita aos utilizadores interagirem com a aplicao.
Figura 5 - XCode4 IDE Na barra lateral esquerda, seleccione o ficheiro PT_AT_PROGViewController.h para definir a interface a utilizar na aplicao. @interface PT_AT_PROGViewController : UIViewController { IBOutlet UILabel *countLabel; IBOutlet UIButton *tapButton; int count; } @end Figura 6 Definio aplicao Tap Counter da interface da
Figura 8 Implementao da UI
43
Exerce funes de consultor de IT na Novabase desde 2008, com experincia de maior relevo nas reas da banca e televiso digital, onde ganhou competncias nas mais vrias tecnologias. Membro da Comunidade NetPonto (http://netponto.org) e autor do blog http://blog.blastersystems.com - Twitter: @brunoacpires
44
An attribute is a piece of additional declarative information that is specified for a declaration." [1] Um atributo um pedao de informao declarativa adicional que especificado para uma declarao.[1]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true,Inherited = false)] public class DescriptionAttribute : Attribute { private String author; private String description; public double version; public DescriptionAttribute(String author, String description) { this.author = author; this.description = description; this.version = 1.0; } } Para controlar o uso deste atributo usamos um outro, AttributeUsage. Aqui dizemos que este atributo vai ser apenas usado em classes passando-lhe o Enum AttributeTargets. Podemos validar a utilizao do atributo em Properties, Mtodos, etc.. Podemos tambm permitir combinaes destes, ou em todos. O campo AllowMultiple indica, que na mesma classe, se pode usar este atributo vrias vezes. O campo Inherited a false refere que, classes que derivem da classe que usa este atributo no tm a mesma informao, ou seja, se necessitarem de o usar tm de o fazer explicitamente. NOTA: uma conveno que se use o sufixo Attribute nos nomes das classes. Tal no obrigatrio pois o compilador procura por classes que herdem de System.Attribute com o nome da classe. Caso no encontre, adiciona a palavra Attribute e repete a pesquisa. Isso considerado no entanto uma boa prtica.
Introduo
Um programa em C#, para alm do cdigo e dos dados, contm tambm metadados. Informao acerca do programa em si. Esses metadados so colocados na aplicao atravs de Atributos. Esses atributos podem existir ao nvel da aplicao, classe, propriedade, mtodo, etc.. Alguns exemplos podem ser vistos dentro do ficheiro AssemblyInfo.cs: [assembly: [assembly: [assembly: [assembly: [assembly: [assembly: AssemblyTitle("MyApplication")] AssemblyDescription("")] AssemblyConfiguration("")] AssemblyCompany("")] AssemblyProduct("MyApplication")] AssemblyCopyright("Copyright 2009")]
Os atributos, definidos ao nvel da aplicao, contm informao da empresa ou pessoa que a desenvolve. Podem depois ser visualizados acedendo s propriedades do ficheiro executvel, aps compilao. Um atributo que j dever ter usado o atributo Serializable. Indica que todos os campos, pblicos e privados, deste tipo podem ser serializados.
Criar um Atributo
Para criar um novo atributo basta criar uma nova classe que derive, directa ou indirectamente, da classe abstracta Attribute: public class DescriptionAttribute : Attribute {
Usar um atributo
Este atributo que acabmos de usar guarda um histrico das classes na nossa aplicao: [Description("Flavio", "Attributes example.")] [Description("Miguel", "Updating version", version=1.1)] public class MyClass { // Codigo do Flavio // Codigo do Miguel } Neste exemplo, numa classe em que j dois programadores participaram podemos ver os dois tipos de parmetros que 45
Aqui temos um atributo vlido em C# que pode ser usado por qualquer classe, property, etc., em qualquer aplicao. No entanto no tem grande utilidade. Vamos adicionar um bocadinho mais de informao a esta classe:
Atributos em C#
os Atributos suportam: posicionais ou com nome. Como parmetros posicionais temos o autor e a descrio. So dois parmetros privados da classe cujo valor passado no construtor. So chamados posicionais pois, no construtor, so definidos pela posio em que esto, primeiro o autor e depois a descrio. O campo verso um campo que referido por nome. No usado na definio do construtor mas passado atravs deste na mesma. Visto ser uma varivel pblica o compilador relaciona o nome da varivel com aquele que passado no construtor. DescriptionAttribute[] attributeArray = (DescriptionAttribute[])type. GetCustomAttributes( typeof(DescriptionAttribute),false); // Se o nosso array estiver vazio porque // esta classe no tem atributos. if (attributeArray.Length == 0) { Console.WriteLine( "A classe {0} no tem atributos do tipo " + "DescriptionAttribute.", type.Name); Console.WriteLine(); } else { // Caso o array tenha objectos vamos // percorre-los e imprimi-los. Console.WriteLine("Atributos do tipo DescriptionAttribute da classe {0}:",type.Name); Console.WriteLine(new string('-', 45)); foreach (DescriptionAttribute description in attributeArray) { / Podemos aceder directamente s // properties que crimos anteriormente. Console.WriteLine( "Programador: " + description.Author + "\n" + "Alterao: " + description.Description + "\n" + "Verso: " + description.Version); } } Agora que temos um mtodo que nos imprime as informaes dos objectos que lhe passmos, vamos us-lo: } Visto que apenas queremos aceder ao que est no atributo, e no alterar o seu valor, podemos implementar apenas os mtodos get. Em seguida precisamos de um mtodo que seja capaz de receber uma instncia de um objecto e imprimir a sua informao. Para tal precisamos de usar reflexo para saber qual o tipo de objecto com que estamos a lidar. De seguida vamos buscar os atributos que queremos para poder enviar a informao para o ecr. A explicao do cdigo encontra-se em comentrio: private static void PrintDevelopersInformation (Object myClass) { // Precisamos de saber qual o tipo // do objecto que recebemos Type type = myClass.GetType(); /* Ao tipo de objecto vamos buscar os atributos * DescriptionAttribute este parmetro opcional. * Se no o colocarmos so devolvidos todos os * atributos. O parmetro "false" indica que no * queremos subir pela cadeia de herana, ou seja, * apenas queremos os atributos desta classe em * particular. Como estamos a pedir uma lista * de um tipo de atributos especifico podemos * fazer o cast */ Console.WriteLine(new string('-', 45));
class Program { static void Main(string[] args) { Program program = new Program(); PrintDevelopersInformation(program); MyClass myClass = new MyClass(); PrintDevelopersInformation(myClass); WaitForKeyPressAndExit(); } private static void PrintDevelopersInformation (Object myClass) { // O nosso cdigo } private static void WaitForKeyPressAndExit() { Console.WriteLine("Press any key to continue."); Console.ReadKey(); } }
46
Atributos em C#
Como se pode ver, instanciamos primeiro um objecto do tipo Program, que no tem o nosso atributo, e chamamos o nosso mtodo. Seguidamente criamos um objecto MyClass, onde colocmos o atributo DescriptionAttribute, e voltamos a chamar o mtodo com este novo objecto. Executando esta aplicao obtemos o seguinte resultado: do nas propriedades das classes, permitimos, ainda, que cada propriedade tenha vrios validadores. Estas caractersticas vo ser utilizadas pelas classes que herdem desta. Esta classe abstracta pois no define comportamento, apenas estrutura. As classes que iro fazer a validao iro herdar desta e sero foradas a implementar o mtodo Validate. Vamos ento criar uma classe que nos informa se um determinado campo um valor inteiro: De seguida precisamos de criar uma classe que verifique a public class IntegerValidatorAttribute : ValidatorAttribute { public override bool Validate(object obj) { int value; if (obj == null) //verificamos se nulo return false; return Int32.TryParse(obj.ToString(),out value); } } validade de um objecto que lhe seja passado. Para simplificar, vamos criar uma classe esttica apenas com o mtodo de validao. Como anteriormente, a explicao do cdigo encontra-se nos comentrios: public static class Validator { public static Boolean checkIfIsValid(Object obj) { // Precisamos de saber qual o // tipo do objecto que recebemos Type type = obj.GetType(); // Com essa informao vamos buscar // as properties do objecto PropertyInfo[] properties = type.GetProperties(); foreach(PropertyInfo prop in properties){ // Para cada property vamos buscar // os objectos de validao ValidatorAttribute[] attributesList = ValidatorAttribute[])
Podemos agora manter e mostrar um histrico das alteraes feitas nas classes dos nossos projectos.
prop.GetCustomAttributes(
typeof(ValidatorAttribute), false); foreach (ValidatorAttribute attribute in attributesList) { // Para cada atributo verificamos // se o valor vlido if (!attribute.Validate(prop.GetValue( obj, null))) return false;
} }
return true;
}}
47
Atributos em C#
Em seguida chamamos a validao do objecto no nosso cdigo: static void Main(string[] args) { ClassTobeValidated classe = new ClassTobeValidated(); Console.WriteLine("Is class valid (" + classe.field+")?" + Validator.checkIfIsValid (classe).ToString()); classe.field = "texto"; Console.WriteLine("Is class valid (" + classe.field+")? "+ Validator.checkIfIsValid (classe).ToString()); classe.field = "12"; Console.WriteLine("Is class valid (" + classe.field+")?" + Validator.checkIfIsValid (classe).ToString()); WaitForKeyPressAndExit(); } Correndo este cdigo obtemos o seguinte resultado: } } Agora podemos usar este validador num objecto. Como teste vamos validar um cdigo postal portugus, sem a localidade: public class ClassTobeValidated { [RegularExpresionValidator(@"^\d\d\d\d-\d\d\d$")] public Object field{ get; set; } } Como sabemos, um cdigo postal em Portugal composto por 4 dgitos mais 3, separados por um hfen. Se tentarmos validar um objecto com vrios valores temos o seguinte resultado: static void Main(string[] args) { ClassTobeValidated classe = new ClassTobeValidated(); Console.WriteLine("Is class valid (" + classe.field+")? " + Validator.checkIfIsValid (classe).ToString()); classe.field = "texto"; Console.WriteLine("Is class valid (" + classe.field +")? " + Validator.checkIfIsValid (classe).ToString()); classe.field = "12"; Console.WriteLine("Is class valid (" + classe.field + ")? " + Validator.checkIfIsValid (classe).ToString()); classe.field = "1234"; Console.WriteLine("Is class valid (" + classe.field + ")? " + Validator.checkIfIsValid (classe).ToString()); classe.field = "2s34-awd"; Console.WriteLine("Is class valid (" + classe.field + ")? " + Validator.checkIfIsValid (classe).ToString()); classe.field = " 1234-123"; Console.WriteLine("Is class valid (" + classe.field +")? " + Validator.checkIfIsValid (classe).ToString()); classe.field = "1234-123 "; Console.WriteLine("Is class valid (" + classe.field +")? " + Validator.checkIfIsValid (classe).ToString()); classe.field = "1234-123"; Console.WriteLine("Is class valid (" + classe.field + ")? " + Validator.checkIfIsValid (classe).ToString()); WaitForKeyPressAndExit(); } return this.expression.IsMatch(obj.ToString());
Como podemos ver, quando passamos a varivel a vazia ou com um texto temos um objecto invlido. Quando passamos uma string que representa um inteiro temos uma resposta vlida. Apesar de ser uma validao relativamente simples (fica a cargo do leitor encontrar formas mais eficientes de verificar a validade do campo), se existissem muitos campos na mesma classe, seria necessrio efectuar vrias vezes a mesma validao. Com um validador basta indicar em cada varivel que validao se pretende fazer. Vamos agora experimentar fazer um validador um pouco mais complexo, que receba um parmetro que indique a validao a ser feita. Vamos criar um validador que recebe uma expresso regular e verifica se o campo no qual usado, vlido segundo essa expresso regular: public class RegularExpresionValidatorAttribute : ValidatorAttribute { // A nossa expressao regular private Regex expression; public RegularExpresionValidatorAttribute(String expression) { // Criamos uma expresso regular com // base na string que recebemos this.expression = new Regex(expression); } public override bool Validate(object obj) { // verificamos se null if (obj == null) return false; // Verificamos se o nosso objecto valido 48
Atributos em C#
Agora que temos um validador mais verstil vamos tentar usar um caso que possa ser usado no mundo real. Ser que conseguimos usar estes objectos para criarmos um objecto Pessoa e garantirmos que os inputs de um utilizador esto correctos? Vamos ento criar um objecto Pessoa com os validadores necessrios. Neste caso vamos usar apenas expresses regulares mas podamos usar qualquer outra que fosse necessria para algum caso mais particular: public class Pessoa { [RegularExpresionValidator(@"^\d{8}$")] public String BI { get; set; } [RegularExpresionValidator(@"(\d+)/(\d+)/(\d{4})")] public String DataNascimento { get; set; } [RegularExpresionValidator(@"^([0-9a-zA-Z]([-.\w]* [0-9a-zA-Z])*@([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA -Z]{2,9})$")] public String Email { get; set; } [RegularExpresionValidator(@"[A-Z]{1}[a-z\.]+")] public String Nome { get; set; } } Agora que temos um stio onde guardar a informao podemos pedir ao utilizador que a insira para podermos fazer a validao: static void Main(string[] args) { Pessoa p = new Pessoa(); Boolean valid; do { Console.Write("Nome: "); p.Nome = Console.ReadLine(); Console.Write("BI: "); p.BI = Console.ReadLine(); Console.Write( "Data de Nascimento (dd/mm/yyyy): "); p.DataNascimento = Console.ReadLine(); Console.Write("Email: "); p.Email = Console.ReadLine(); valid = Validator.checkIfIsValid(p); Console.WriteLine("Os dados desta pessoa so vlidos: " + valid); }while(!valid); WaitForKeyPressAndExit(); O resultado ser alguma coisa semelhante a isto:
Fica ao cargo do leitor perceber qual, ou quais, os motivos que fizeram a primeira tentativa falhar.
Concluso
Os atributos so um recurso extremamente til para evitar que tenhamos de repetir muitas vezes o mesmo cdigo. Podendo ser usado em classes, propriedades, mtodos, etc, ficam associadas ao elemento onde so utilizadas podendo ser facilmente acedidas. Podem ser usadas tanto por motivos informativos, bem como para ter um determinado comportamento, o que permite abstrair da implementao e focar apenas na sua funcionalidade.
Referncias
[1] - MSDN (ms-help://MS.MSDNQTR.2002APR.1033/
csspec/html/vclrfcsharpspec_17_2.htm) http://www.radsoftware.com.au/articles/ regexlearnsyntax.aspx http://oreilly.com/windows/archive/csharp-regularexpressions.html
Escrito por Flvio Geraldes Licenciou-se em Engenharia Informtica e Computadores no Instituto Superior Tcnico tendo-se especializado na rea de Programao e Sistemas de Informao. Aps a finalizao do curso juntou-se Sybase SBS Software onde teve oportunidade de trabalhar com vrias tecnologias focando-se particularmente em .NET. Actualmente consultor da Sybase SBS Software numa empresa de telecomunicaes onde responsvel pelo desenho e desenvolvimento de vrias aplicaes.
49
Introduo
Se nunca usou tipos genricos, provavelmente utiliza um array para guardar dados/objectos, no entanto a utilizao desta estrutura tem algumas desvantagens relativamente aos genricos, como o tamanho fixo, ao contrrio dos tipos genricos que podem ser expandidos de forma dinmica, a falta de mtodos especializados para trabalhar com objectos, so strongly typed no permitindo colocar valores de tipos diferentes, etc. Com este artigo, pretendo atravs da utilizao uma classe Automovel e atravs da elaborao de Console Applications e de vrias analogias mostrar como poder utilizar alguns dos tipos genricos da linguagem Visual Basic 2010, da forma mais simples e acessvel possvel.
List(Of T)
A lista, provavelmente o tipo mais bsico que podemos aplicar, pois apenas uma lista. Existem vrios mtodos que podemos aplicar lista, no exemplo seguinte, iremos ver alguns:
Sub ListaNumeros() Dim lista As New List(Of Integer) From
{4, 1, 2, 3}
'Adiciona um novo elemento lista lista.Add(5) 'Mostra o contedo da lista Console.WriteLine("Lista Inicial") For Each a As Integer In lista Console.WriteLine(a.ToString()) Next 'Escreve o nmero de elementos da lista Console.WriteLine(vbLf & "Numero de Elementos da Lista") Console.WriteLine(lista.Count) 'Ordenar a lista lista.Sort() 'Mostra a lista ordenada Console.WriteLine(vbLf & "Lista Ordenada" & vbLf) For Each a As Integer In lista Console.WriteLine(a.ToString()) Next 'Remove a primeira instncia do item indicado 'para apagar que se encontra na 3 posio lista.Remove(2) 'Remove o nmero numa determinada posio 'para apagar o valor que se encontra no 'ndice 1 (2 casa do array) lista.RemoveAt(1) Console.WriteLine(vbLf & "Lista aps apagar os elementos" & vbLf) For Each a As Integer In lista Console.WriteLine(a.ToString()) Next Console.Read() End Sub 51
Passando desde j aco, dever ento criar a classe base sobre a qual iremos criar os objectos para os diferentes tipos genricos que iremos utilizar neste artigo. Public Class Automovel Public Property Cilindrada() As Integer Public Property Marca() As String Public Property Modelo() As String Public Sub New() 'Permite no definir valores no construtor End Sub Public Sub New(ByVal cilindrada As Integer, ByVal marca As String, ByVal modelo As String) Me.Cilindrada = cilindrada Me.Marca = marca Me.Modelo = modelo End Sub Public Overrides Function ToString() As String Return String.Format( "{0} {1} com {2} cc de cilindrada", Marca, Modelo, Cilindrada) End Function End Class
Tipos Genricos
O output obtido o seguinte: lista.Sort() Uma nota muito importante, que neste caso, como estamos a trabalhar com a classe Integer, a ordenao bastante simples e lgica (ordem crescente). Lista com Objectos Agora, vamos criar uma lista de objectos, utilizando para isso a classe Automovel anteriormente definida Sub Lista() 'Criar a lista e inserir alguns automveis Dim automoveis As New List(Of Automovel) From { New Automovel() With {.Marca = "Ford", .Modelo = "Fiesta", .Cilindrada = 1200}, New Automovel() With {.Marca = "Opel", .Modelo = "Corsa", .Cilindrada = 1400} } 'Mostra o total de carros na lista Console.WriteLine( "A lista possui {0} automveis", automoveis.Count) 'Adiciona um novo automvel no final da lista automoveis.Insert(automoveis.Count, New Automovel() With { .Marca = "Citroen", .Modelo = "Saxo", .Cilindrada = 1100 } ) 'Insere o objecto na ltima posio automoveis.Add(New Automovel() With { .Marca = "Nissan", .Modelo = "Qashqai", .Cilindrada = 1200 } ) 'Mostra o contedo da lista For Each a In automoveis Console.WriteLine(a.ToString()) Next 'Mostra apenas a marca For Each a In automoveis Console.WriteLine(a.Marca) Next Console.Read() End Sub
No incio, temos a lista com os elementos pela ordem que foram inseridos atravs das seguintes instrues:
Dim lista As New List(Of Integer) From {4, 1, 2, 3} lista.Add(5)
Atravs da primeira instruo, crimos a lista e inicializmola com os valores inteiros 4, 1, 2 e 3, e de seguida com a segunda linha, acrescentmos mais um valor, o valor 5. Neste momento, podemos esquematizar a lista da seguinte forma:
importante compreender que o primeiro elemento da lista, encontra-se na posio 0, e no na 1. Este um erro comum e neste momento qualquer tentativa de referncia posio 5 por exemplo, resultar no lanamento de uma excepo e se tentar apagar o elemento 4 enviando como parmetro o ndice (posio) 1, ir apagar o elemento 1. Depois tempoa seguinte linha de cdigo: For Each a As Integer In lista Console.WriteLine(a.ToString()) Next
Este o iterador For Each, que tem como objectivo percorrer uma estrutura de dados (array ou genrico), sem ser necessrio indicar o tamanho da mesma, foi tambm declarada uma varivel a do tipo dos elementos da lista (inteiro neste caso), para que possa guardar o valor do elemento que se encontra na posio actual. Mais frente, fizemos uma ordenao lista, atravs da seguinte instruo:
52
Tipos Genricos
Vamos ento ver, um pouco mais em detalhe, alguns mtodos que utilizmos: Public Class OrdenarporCilindrada Implements IComparer(Of Automovel)
Count() - Retorna o nmero de objectos que a lista possui Insert(Indice As Integer, Objecto) - Adiciona o objecto especificado no segundo parmetro na posio indicada pelo ndice, para adicionar ao fim da lista, podemos utilizar automoveis.count Add(Objecto) - Adiciona o objecto no final da lista
Public Function Compare(ByVal x As Automovel, ByVal y As Automovel) As Integer Implements System.Collections.Generic.IComparer(Of Automovel).Compare If x.Cilindrada > y.Cilindrada Then Return 1 End If If x.Cilindrada < y.Cilindrada Then Return -1 Else Return 0 End If End Function
End Class Se no entendeu o cdigo da funo Compare, no fique preocupado! Estamos apenas a informar a interface como que queremos que a comparao seja feita. Se retornarmos 0, isso significa que ambos os objectos so iguais, no caso de retornarmos 1 ou -1, isso significa que o primeiro objecto maior ou menor que o segundo, respectivamente. Seguidamente, no Sub em que utilizamos a lista, devemos acrescentar o seguinte cdigo:
Na primeira linha, podemos ver o resultado de ter corrido a instruo nomedalista.Count, que retorna o nmero de elementos que possui, neste caso retornou 2, porque era o nmero de automveis que a lista possua aquando da sua inicializao. Depois foram inseridos mais dois automveis, e atravs do iterador For Each, percorreu-se a lista, gerando as 4 prximas linhas, que contm o retorno do mtodo toString dos objectos, mostrando assim informaes sobre os mesmos. Finalmente temos as marcas dos automveis, resultado de termos feito um Console.Writeline s vrias posies do array.
Console.WriteLine( "===========LISTA ORDENADA==========") 'Mostra o contedo da lista For Each a In Automoveis Console.WriteLine(a.ToString()) Next
Ordenar a Lista
Se desejarmos ordenar a lista, poderemos usar o mtodo Sort e como parmetro enviar uma classe que implemente a interface iComparer.
Para isso, e para que possamos ordenar os automveis por cilindrada, vamos ento criar uma classe OrdenarPorCilindrada, para que possamos utilizar como parmetro do Sort, e desta forma ordenar os objectos:
53
Tipos Genricos
Poderemos tambm, utilizar a interface IComparable, que ao contrrio da IComparer que se define numa classe parte e depois enviada como parmetro da funo Sort, a IComparable definida directamente na prpria classe dos objectos da lista (neste caso a classe automvel), um exemplo de implementao o seguinte: Public Class Automovel Implements IComparable Public Property Cilindrada() As Integer Public Property Marca() As String Public Property Modelo() As String Public Sub New() 'Permite no definir valores no construtor End Sub Public Sub New(ByVal cilindrada As Integer, ByVal marca As String,ByVal modelo As String) Me.Cilindrada = cilindrada Me.Marca = marca Me.Modelo = modelo End Sub Public Overrides Function ToString() As String Return String.Format( " {0} {1} com {2} cc de cilindrada", Marca, Modelo, Cilindrada) End Function Public Function CompareTo(ByVal obj As Object) As Integer Implements System.IComparable.CompareTo Dim temp As Automovel = TryCast(obj, Automovel) If temp IsNot Nothing Then If Me.Cilindrada > temp.Cilindrada Then Return 1 ElseIf Me.Cilindrada < temp.Cilindrada Then Return -1 Else Return 0 End If Else Throw New ArgumentException( "O parmetro no um automvel") End If End Function End Class Basicamente, adicionmos o Inherits IComparable para implementar a classe, e depois definimos a funo CompareTo, para explicitar a forma como queremos que os objectos da classe sejam ordenados, neste caso e como, mais uma vez, queremos que sejam ordenados por cilindrada, a implementao da funo CompareTo bastante semelhante compare que utilizmos na interface IComparer, com a diferena que em vez de variveis como a x e a y, utilizmos o prprio 54 objecto (Me) e o objecto a comparar, para a qual definimos uma varivel temp. Para fazer a ordenao da lista, basta executar a seguinte instruo:
automoveis.Sort()
Esta instruo funciona, porque o mecanismo de ordenao est definido na prpria classe. Ordenao Alfabtica Se desejarmos, tambm podemos ordenar alfabeticamente a lista, neste caso, poderamos implementar o Compare da interface IComparer, criando uma classe OrdenarporMarca com o seguinte cdigo de modo a ordenar por marca:
Public Class OrdenarporMarca Implements IComparer(Of Automovel) Public Function Compare(ByVal x As Automovel, ByVal y As Automovel) As Integer Implements System.Collections.Generic.IComparer(Of Automovel).Compare If x.Marca > y.Marca Then Return 1 End If If x.Marca < y.Marca Then Return -1 Else Return 0 End If End Function End Class Poder ento concluir, que o processo de ordenao por ordem alfabtica, bastante semelhante ao dos nmeros. Aps correr o cdigo, ter ento o output desejado:
A Classe Stack(Of T)
Uma stack, em portugus pilha, uma estrutura LIFO (Last in First Out), em que o ltimo objecto colocado, o primeiro a sair. Um exemplo da vida real, uma srie de livros colocados uns em cima dos outros, o primeiro a entrar, fica em baixo, logo se o formos retirar da pilha, este ser o ltimo, pois teremos de remover primeiro todos os que esto em cima deste, ou seja, os ltimos que foram colocados, ficam em cima da pilha, e desta forma so os primeiros a sair.
Tipos Genricos
Esta classe, usa os mtodos Push() e Pop() para carregar itens para cima da pilha ou remov-los respectivamente, poder utilizar tambm o mtodo Peek(), para visualizar o objecto do topo, sem o remover. Um exemplo de utilizao desta estrutura o seguinte Sub usarStack() Dim stackAutomoveis As New Stack(Of Automovel) 'Adicionar os Carros stackAutomoveis.Push(New Automovel With { .Marca = "Ford", .Modelo = "Fiesta", .Cilindrada = 1200}) stackAutomoveis.Push(New Automovel With { .Marca = "Opel",.Modelo = "Corsa", .Cilindrada = 1400}) 'Mostra o item do topo da pilha sem o remover Console.WriteLine("O Automovel do topo : {0}", stackAutomoveis.Peek()) 'Remove o automvel do topo da pilha Console.WriteLine( "Pop!, o automvel {0} foi removido!", stackAutomoveis.Pop()) 'Fazendo o peek de novo Console.WriteLine( "Agora o automovel do topo : {0}", stackAutomoveis.Peek()) Console.Read() End Sub A consola ir ento mostrar o seguinte: 'Verifica, sem remover, remove e retorna o objecto que se encontra na frente da fila (o primeiro que adicionmos), o Enqueue() que adiciona um objecto para a parte de trs da fila (na vida real, o que acontece quando entramos numa fila, ficamos na ltima posio), e finalmente, o bem conhecido do Stack, o Peek() que retorna o primeiro objecto que adicionmos sem o apagar. Passemos ento aco, e vamos pr a fila a trabalhar: Sub Fila() 'Adicionar 2 automveis fila Dim filadeAutomoveis As New Queue _ (Of Automovel)()
filadeAutomoveis.Enqueue( New Automovel With { .Marca = "Ford", .Modelo = "Fiesta", .Cilindrada = 1200}) filadeAutomoveis.Enqueue( New Automovel With { .Marca = "Opel", .Modelo = "Corsa", .Cilindrada = 1400}) 'Temos ento uma fila de 2 automveis, 'o Fiesta, encontra-se frente do Corsa
Correndo o cdigo, obtemos o seguinte output: Na primeira linha, vemos o ltimo objecto que adicionmos, que o Opel Corsa, no entanto este no foi removido, pois foi utilizado o mtodo peek() que apenas permite ver qual o objecto. Seguidamente, usmos o mtodo pop, que para alm de remover o objecto, retorna o mesmo e por ltimo, vemos o primeiro objecto que adicionmos, o Ford Fiesta. Na prxima estrutura, a queue, vamos ver como se pode mostrar os objectos pela ordem em que os adicionmos.
A Classe Queue(Of T)
Quando estamos na fila de um supermercado, o primeiro a chegar, o primeiro a ser atendido e consequentemente, o ltimo a chegar, o ltimo a ser atendido. Este o funcionamento da Queue (fila em portugus), que em vez de LIFO, funciona como FIFO (First In First Out), ou seja, o primeiro a entrar o primeiro a sair. Os principais mtodos desta classe so o Dequeue(), que
Para este cdigo, imaginemos que o Ford Fiesta e o Opel Corsa encontram-se numa fila para uma bomba de gasolina, o Ford Fiesta vai frente, pois foi o primeiro a ser adicionado. Primeiro, atravs do peek, vimos qual era o automvel que ia frente, depois com o dequeue, fizemos com que o objecto fosse retornado e removido da lista, ou seja, o automvel abasteceu e saiu da bomba. Seguidamente, o Corsa que estava atrs do Fiesta, passa para a frente da fila, abastecido e tambm sai da mesma. 55
Vamos agora analisar o output linha a linha. Na 1 linha, aparece a palavra True, isto deve-se ao facto de termos invocado a funo ContainsKey, esta funo recebe como parmetro uma chave, e quando executada, verifica se existe na coleco um objecto com essa chave, retornando um valor booleano (true caso exista, false se no existir). Neste caso como retornou true, existe um automvel com essa matrcula, poderamos tambm formatar a resposta atravs de uma condio deste gnero:
Nomedodicionario.Add(123456789,Joo Silva)
If setAutomoveis.ContainsKey("20-82-BT") Then Desta forma, adicionmos o objecto, neste caso a String Joo Silva, com o identificador 123456789. Mas como de automveis que temos falado, vamos ento ver o exemplo: Sub Dicionario() Dim setAutomoveis As New Dictionary _ (Of String, Automovel) setAutomoveis.Add("20-82-BT", New Automovel With {.Marca = "Ford", .Modelo = "Fiesta", .Cilindrada = 1200}) setAutomoveis.Add("20-82-JM", New Automovel With {.Marca = "Citroen", .Modelo = "Saxo",.Cilindrada = 1300}) 'Verifica se o objecto com uma 'determinada chave existe If setAutomoveis.ContainsKey("20-82-BT") Then Console.WriteLine("Existe") Else Console.WriteLine("No Existe") End If Console.WriteLine _ (setAutomoveis.ContainsKey("20-82-BT")) 'Escreve o objecto com a chave("20-82-BT") Console.WriteLine _ (setAutomoveis.Item("20-82-BT")) 'Mostra os objectos do dicionrio e chaves Dim par As KeyValuePair _ (Of String, Automovel) For Each par In setAutomoveis Console.WriteLine( "{0} a matricula do {1}", par.Key, par.Value) Next Console.Read() End Sub 56 Console.WriteLine("Existe um automvel com essa matrcula") Else
Desta forma, se o objecto existir ir ser escrita uma mensagem bastante mais amigvel para o utilizador. Passando para a segunda linha, aqui utilizmos a funo ContainsKey, que recebeu como parmetro a matrcula (chave) do automvel (objecto) e escreveu a descrio deste, utilizando para isso a funo ToString definida na sua classe (Automvel no caso deste exemplo). De seguida, as duas ltimas linhas so o resultado de, utilizando o KeyValuePair que define um par valor-chave do tipo String, para que possa ser depois escrito atravs do iterador For Each utilizado na linha seguinte que ir percorrer a coleco e, recorrendo ao mtodo ToString, escrever a descrio dos objectos.
A Classe SortedDictionary(Of T)
Este genrico bastante semelhante ao anterior, no entanto aqui os objectos sero ordenados por ordem crescente chave. Por isso, aqui irei apenas apresentar um pequeno exemplo para que compreendam a diferena entre estes dois genricos, para isso iremos adicionar dois objectos a cada uma das coleces, e depois correr um iterador, tal como exemplificado no exemplo anterior de modo a percorrer ambas as coleces.
Tipos Genricos
Sub SortedDictionary() Dim setAutomoveisOrd As New _ SortedDictionary(Of String, Automovel)() Dim setAutomoveis As New _ Dictionary(Of String, Automovel) setAutomoveisOrd.Add( "20-82-BT", New Automovel {.Marca = "Ford", .Modelo = "Fiesta", .Cilindrada = 1200}) setAutomoveisOrd.Add( "16-82-JM", New Automovel {.Marca = "Citroen", .Modelo = "Saxo", .Cilindrada = 1300}) setAutomoveis.Add( "20-82-BT", New Automovel {.Marca = "Ford", .Modelo = "Fiesta", .Cilindrada = 1200}) setAutomoveis.Add( "16-82-JM", New Automovel {.Marca = "Citroen", .Modelo = "Saxo", .Cilindrada = 1300})
With De modo a percebermos melhor o que aconteceu aqui, reparemos na ordem em que os objectos foram inseridos, primeiro um com matrcula (chave) iniciada por 20 e de seguinte outro com matrcula iniciada por 16, estando assim desordenados. Quando corremos o iterador sobre o dicionrio, estes foram impressos na ordem em que foram inseridos, enquanto que no caso do SortedDictionary, estes foram impressos por ordem crescente de chave (matrcula). esta a diferena entre estes dois genricos.
With
With
With
Concluso
Depois de ler este artigo, e se nunca utilizou estas estruturas nos seus programas, espero que agora sejam uma espcie de amigos inseparveis e os utilize nos seus prximos programas que necessitem de guardar objectos, pois com isso vai ter imensas vantagens.
Console.WriteLine("=Dictionary=") Dim par As KeyValuePair(Of String,Automovel) For Each par In setAutomoveis Console.WriteLine( "{0} a matricula do {1}", par.Key, par.Value) Next Console.WriteLine("=SortedDictionary=") Dim par2 As KeyValuePair(Of String,Automovel) For Each par2 In setAutomoveisOrd Console.WriteLine( "{0} a matricula do {1}", par2.Key, par2.Value) Next Console.Read() End Sub
Neste artigo, foram abordados apenas alguns dos inmeros mtodos que poder aplicar a cada um dos genricos, poder ver mais consultando a seco do namespace System.Collections.Generic que se encontra no website http:// msdn.microsoft.com/en-us/library/0sbxh9x2.aspx . Neste endereo, poder para alm das funes, ver tambm um conjunto de interfaces teis que poder aplicar nas suas coleces, para alm da iComparer que foi utilizada no exemplo do SortedSet.
Apesar de existirem mais tipos genricos, penso que os bsicos e mais utilizados foram abordados.
Escrito por Fbio Domingos Estudante de Gesto de Sistemas de Informao na Escola Superior de Cincias Empresariais do Instituto Politcnico de Setbal, tem como principal hobbie a informtica, nomeadamente as reas de programao, bases de dados e IT Support. moderador global do frum Portugal-a-Programar, membro do staff desta revista e por vezes contribui com solues para a comunidade Experts-Exchange.
57
Introduo
Ultimamente tem-se falado muito sobre o Cloud Computing e sobre as diversas ofertas que se encontram disponveis, e ainda mais sobre como esta nova forma de computao permite que os nossos negcios passem a ser cada vez mais globais. Com isso conseguimos atingir novos mercados, e novos utilizadores. Sem dvida que todas estas questes so verdadeiras, pois uma vez na Internet as nossas solues passam imediatamente a dispor de uma presena global e utilizvel por qualquer utilizador de qualquer local do mundo, mas a questo que muitas vezes se coloca , a que preo e como que qualidade esto esses utilizadores a ser servidos? Sem dvida que esta uma questo importante, e que pode tornar as nossas solues mais ou menos conhecidas. Porque nos devemos preocupar? Estas so preocupaes que deveremos ter seriamente em considerao quando disponibilizamos uma soluo no mercado gobal, uma vez que a Experincia de Utilizao (UX) um dos pontos mais importantes para que a nossa soluo seja mais ou menos utilizada, e um dos pontos importantes na UX sem dvida a performance da mesma, uma vez sabemos que os utilizadores no gostam de esperar demasiado tempo por uma pgina, ou por fazer uma determinada operao, pois completamente diferente uma soluo que responde num perodo de 1 a 3 segundos, de uma que responde entre 10 a 30 segundos, pois a produtividade vai decrescer significativamente, e esse aspecto ser tido em conta no momento da aquisio ou no dessa mesma soluo. Por isso mesmo um ponto muito importante a reter que A PERFORMANCE muito Importante. Passemos ento a ilustrar estes aspectos olhando para o mapa da disperso dos Data Centers de Windows Azure da Microsoft , e analisando como a performance ser afectada com base nas decises que efectuamos sobre em que Data Center disponibilizar a soluo.
Figura 1 Disponibilizao da soluo no Data Center de Western Europe. Com base nesta figura vamos analisar o que acontecer no caso de disponibilizar-mos a nossa soluo no Data Center de Windows Azure identificado como Western Europe. O que este grfico indica que a regio mais prxima ir obter tempos de latncia de cerca de 50 milissegundos, o que significa que tero uma performance bastante boa no acesso nossa soluo, mas medida que nos afastamos do local em que disponibilizamos a nossa soluo o tempo de latncia vai duplicando, para 100 ms, 200ms, e assim sucessivamente. O que significa que neste caso se estivermos a tentar abordar o mercado dos Estados Unidos teremos certamente questes de performance bastante importantes que deveremos ter em conta. Tambm importante no momento da escolha do Data Center a utilizar ser o site http://latency.cloudapp.net ou o http:// metricstest.cloudapp.net/ que so dois sites de estatsticas e grficos de tempos de latncia produzido por Matthew Rosoff. Aqui poderemos o tempo de latncia mdio entre zonas.
Figura 2 Tempos de Latncia entre Zonas Mas se explorarmos um pouco mais o site conseguimos ter informao sobre o histrico dos tempos de latncia entre dois Data Centers, como por exemplo Western Europe e North-Central US.
Figura 3 Histrico do Tempo de latncia entre Western Europe e North-Central US para as ltimas 24 horas
59
Figura 4 Disperso geogrfica da soluo Provavelmente a resoluo mais bvia para este problema seria a de disponibilizar a nossa soluo nos diversos Data Centers disponveis e a partir da, efectuar o redireccionamento dos clientes para cada um dos Data Centers dependendo da sua localizao. Sendo uma soluo mais ou menos bvia levanta alguns problemas, como por exemplo:
Como ser efectuado o redireccionamento dos pedidos? Como deverei efectuar o balanceamento dos pedidos? Como deverei redireccionar os pedidos em caso de problemas num dos Data Centers? Como resolver o problema do endereo, visto que cada uma das disponibilizaes em cada Data Center tem um endereo nico?
Estas so sem dvida questes complexas que necessitam de resposta de forma a que possamos ter uma soluo efectiva para o problema. Para demonstrar esta soluo iremos olhar para o Laboratrio presente no Windows Azure Traning Kit em http:// bitly.com/WATrainingKit, ou que poderemos obter o cdigo fonte aqui http://bit.ly/WATrafficManagerLabSource e o guia de acompanhamento do laboratrio aqui http://bit.ly/ WATrafficManagerLabGuide.
60
Agora que j temos as solues a funcionar nos 3 Data Centers embora os problemas mantm-se.
Como ser efectuado o redireccionamento dos pedidos? Como deverei efectuar o balanceamento dos pedidos? Como deverei redireccionar os pedidos em caso de problemas num dos Data Centers? Como resolver o problema do endereo, visto que cada uma das disponibilizaes em cada Data Center tem um endereo nico?
1. Internamente preenchida a tabela de tempos de latncia entre Data Centers 2. Quando o cliente efectua um pedido para o endereo do Windows Azure Traffic Manager, a poltica a utilizar identificada como sendo de performance. 3. O Traffic Manager consulta a tabela de tempos de latncia e define qual o melhor/ mais prximo para o cliente em questo. 4. Com base nessa definio o cliente redireccionado para o Data Center escolhido 5. No momento da seleco reservado para o cliente, durante um perodo de tempo definido no momento da criao da poltica de balanceamento, o DNS que foi seleccionado. 6. Todos os prximos pedidos sero efectuados directamente ao DNS escolhido durante o tempo definido para expirao da reserva. Criao da Politca Em primeiro lugar deveremos abrir o Windows Azure Management Portal, e seleccionar a opo Virtual Network
Em seguida seleccionamos o Traffic Manager -> Policies, e seleccionamos o Create, onde iremos criar uma poltica de balanceamento, e para isso iremos definir:
61
O Resultado Tendo em conta a configurao que acabamos de efectuar, se efectuarmos o pedido de Portugal, obtemos a soluo que se encontra disponvel no Oeste da Europa.
A resposta est a ser servida pelo Data Center mais prximo. E se agora, por algum motivo, uma das publicaes no estiver disponvel? O que acontece? Para isso vamos desactivar o balanceamento de trfego do Este da Asia. Se agora tentarmos aceder novamente ao nosso endereo do Traffic Manager, o resultado ser que o trafego ser imediatamente redireccionado para o Data Center do Centro Sul dos Estados Unidos.
Se procurarmos compreender quem nos est a responder utilizando o comando nslookup, obtemos o seguinte resultado:
62
Mtodo de Balanceamento: Round-Robin Hosted Services disponveis na subscrio que devero ser considerados, aqui a ordem ser importante uma vez que ser pela mesma que o balanceamento ir girar. Endereo de Monitorizao: /AppHealth (ir auxiliar a aplicao a conhecer qual o estado de cada uma das politicas). DNS do Traffic Manager: roundrobin.nfgworldapp.ctp.trafficmgr.com (este ser o endereo que iremos utilizar para obtermos o balanceamento por round robin). e finalmente o DNS TTL: 30 segundos (define o tempo em que o DNS reservado para o cliente, e neste caso curto para facilitar os testes).
Round Robin
Uma outra opo para o balanceamento do trfego disponibilizado pelo Windows Azure Traffic Manager, o RoundRobin, sendo que este o mais simples uma vez que vai balanceando os pedidos para cada um dos Data Centers com as publicaes da nossa soluo sequencialmente. A Teoria
O Resultado Agora que temos a poltica de Round Robin criada, vamos passar a verificar se a mesma funciona efectivamente, e para isso vamos efectuar um pedido e recebemos a primeira resposta a partir do Data Center de Este da sia.
1.
2. 3.
4. 5.
O cliente efectua um pedido para o endereo do Windows Azure Traffic Manager, a poltica a utilizar identificada como sendo de round robin. Verifica qual o DNS que foi servido por ltimo. Serve o prximo DNS da lista efectuado a reserva para o cliente, durante um perodo de tempo definido no momento da criao da poltica de balanceamento, o DNS que foi seleccionado. Actualiza a propriedade que identifica qual o ultimo DNS servido a clientes. Todos os prximos pedidos sero efectuados directamente ao DNS escolhido durante o tempo definido para expirao da reserva.
63
4.
Criao da Poltica Em primeiro lugar deveremos abrir novamente o Windows Azure Management Portal, e seleccionar a opo Virtual Network. Seguidamente seleccionamos o Traffic Manager -> Policies, e seleccionamos o Create, onde iremos criar uma poltica de balanceamento, e para isso iremos definir: Se por alguma razo um dos Data Centers, ou uma das solues deixar de responder, ento iremos imediatamente deixar de ser balanceados para esse mesmo Data Center. Concluso Com base nos testes efectuados anteriormente poderemos afirmar que, o Windows Azure Traffic Manager, resolve tambm o problema de balanceamento de carga, se objectivo for apenas distribuir uniformemente os pedidos, independentemente dos tempos de latncia.
Mtodo de Balanceamento: Failover Hosted Services disponveis na subscrio que devero ser considerados, aqui a ordem ser importante pois ser a forma de definir qual o DNS principal e a ordem pela qual ser utilizado em caso de falha. Endereo de Monitorizao: /AppHealth (ir auxiliar a aplicao a conhecer qual o estado de cada uma das polticas). DNS do Traffic Manager: failover.nfgworldapp.ctp. trafficmgr.com (este ser o endereo que iremos utilizar para obtermos o balanceamento por failover). e finalmente o DNS TTL: 30 segundos (define o tempo em que o DNS reservado para o cliente, e neste caso curto para facilitar os testes).
Failover
Por fim existe ainda um outro mecanismo de balanceamento que denominado de Failover, uma vez que define a ordem pela qual o balanceamento dever ser efectuado em caso de a publicao principal da soluo no se encontrar disponvel. A Teoria 1. O cliente efectua um pedido para o endereo do Windows Azure Traffic Manager, a poltica a utilizar identificada como sendo de failover. O sistema verifica se o DNS principal (definido como sendo o que se encontra em primeiro na lista da definio da politica) se encontra disponvel. 64
2.
Continuidade e fiabilidade do negcio (Failover) Diminuio do Tempo de latncia e aumento da performance (Performance)
Escalabilidade das solues (Performance) Distribuio de Carga (Round Robin) Manuteno (Desligar o Trfego para um DNS Disable
Traffic)
Mas se por algum motivo o DNS principal no se encontrar disponvel seremos imediatamente redireccionados para o DNS seguinte da lista, e assim sucessivamente. Neste caso o DNS secundrio refere-se ao DNS do Este da sia.
No existe SLA para este servio No pago No neste momento recomendado para utilizao em
produo, uma vez que no existe um SLA
Mtodos de balanceamento Performance Round Robin Failover Configurabilidade do TTL (Time to Live) do DNS Monitorizao via HTTP ou HTTPs em qualquer porta Criao, Visualizao, Actualizao e Remoo de polticas de balanceamento
Capacidade de Ligar e Desligar polticas de Trfego Capacidade de Ligar e Desligar balanceamento de trfego para um determinado DNS.
Resumo
Em resumo, o Windows Azure Traffic Manager um Balanceador de Trfego Global, que se encontra actualmente na sua verso CTP, e que permite resolver diversos problemas em termos de melhoramento da Experincia de Utilizao (UX), das nossas solues, uma vez que nos permite que atravs de polticas como as de Performance, Round Robin ou Failover definir a forma como esse balanceamento efectuado, resolvendo desta forma simples e eficaz um problema que muito nos preocupa quando queremos globalizar as nossas solues e os nossos negcios. Ainda para mais o processo bastante simples, pois apenas necessitamos de 3 passos para o conseguir: 1. Publicar a soluo para os vrios Data Centers a utilizar. 2. Criar as polticas de balanceamento de trfego. 3. Utilizar Com estes 3 passos bastante simples conseguimos ter uma soluo global, fivel e ao mesmo tempo de elevada Experincia de Utilizao, permitindo-nos por isso mesmo chegar mais e melhor aos nossos potenciais clientes, e com isso melhorar os nossos negcios. Espero que com este artigo vos tenha ajudado a compreender melhor o que afinal o Windows Azure Traffic Manager e ao mesmo tempo desmistificar a forma de funcionamento, os resultados esperados, e acima de tudo as vantagens para o negcio. Claro que muito ficou por dizer em termos de monitorizao das polticas, boas prticas, etc, mas ficou aqui o que me pareceu mais essencial, e em futuros artigos poderemos ento falar em maior detalhe sobre esses assuntos.
Histrico de alteraes das polticas de trfego Balanceamento Geogrfico - este balanceamento ser
efectuado com base na definio que de regies que efectuarmos, sendo que poderemos definir que DNS dever responder a que regio ou pas de origem.
Hierarquia de polticas Verificao do estado das polticas Criao de regies medida Criao de regras de monitorizao Alertas
Agora que j sabemos tudo sobre o que existe actualmente na verso CTP, o que poderemos esperar no futuro, como funciona, etc, uma das questes que poder estar a surgir sem dvida, Quando poderemos ter a verso final? Esta uma excelente questo pois no existe para j uma data fixa assumida pela Microsoft, sendo que a nica coisa que sabemos efectivamente que esta verso CTP foi disponibilizada no MIX no dia 12 de Abril de 2011, e que terminar no final do Vero. Sendo que estamos no vero e o mesmo termina a dia 23 de Setembro, estamos realmente muito perto de saber alguma novidade sobre este assunto. Se pensarmos ainda que durante o ms de Setembro vai existir uma grande conferncia da Microsoft denominada Build, provavelmente teremos uma resposta nessa altura. Mas mais uma vez, no existe uma data assumida pela Microsoft.
Nota: No vale a pena tentarem aceder aos endereos dos testes, pois os mesmos j se encontram invlidos, uma vez que a soluo foi disponibilizada e utilizada apenas para os testes relativos escrita deste artigo.
Escrito por Nuno Godinho Consultor Independente com 10 anos de Experincia e principal responsabilidade de ajudar os clientes a identificar, planear, gerir e desenvolver solues e produtos de software. Especialista em Tecnologias Microsoft. Orador em alguns dos maiores eventos de desenvolvimento da Microsoft Portugal como MSDN, TechDays, DevDays, alm de eventos internacionais como TechEd Europa, TechEd Online Worldwide, MVP Nation e CloudViews.Org. Microsoft MVP h 4 anos, inicialmente em ASP.NET e a partir do incio deste ano em Windows Azure com blogs em http://www.pontonetpt.com/blogs/nunogodinho (Portugus e Ingls) e http://www.msmvps.org/blogs/nunogodinho (Ingls), INETA Country Leader por Portugal, e parte da equipa de gesto de por diversas comunidades Portuguesas como PontoNetPT, XAMLPT e Fundador da AzurePT (Windows Azure em Portugus).
66
http://www.sqlport.com
A Microsoft SQL Server uma das bases de dados mais populares do mundo, e qualquer developer profissional ou amador j se deve ter deparado uma ou mais vezes com ela. Independentemente do tamanho da empresa - seja pequena ou grande, trabalhando com C#, VB.NET ou JAVA, uma vasta maioria dos profissionais, j escreveu algumas linhas de cdigo para esta base de dados que no pra de ganhar adeptos por todo o mundo. Neste artigo eu pretendo referir algumas opes e ferramentas gratuitas que podem facilitar e acelerar o trabalho com SQL Server. A SQL Server Management Studio (SSMS) est instalado junto com SQL Server e pode ser instalado tanto em conjunto com o servidor, como em separado. Mesmo a verso Express de SQL Server tem a sua verso de SSMS, que um pouco limitada em relao verso paga (no se pode trabalhar com Analysis Services, Reporting Services, Notification Services ou SQL Server Agent, por exemplo) mas mesmo assim permite trabalhar com todas as verses de bases de dados SQL Server desde 2000. Muitos profissionais que trabalham com SQL Server 2000 escolhem instalar o SSMS para ter algumas das funcionalidade avanadas que esta ferramenta oferece. Eu prprio enquanto trabalho com SQL Server 2005, utilizo a SSMS de 2008 se for possvel instalar num computador. A vasta maioria de profissionais e amadores utilizam SSMS nos seus trabalhos, e por isso eu queria partilhar algumas das funcionalidades de SSMS que eu aprecio, mas que considero serem um pouco desconhecidas do utilizador menos avanado.
mas opes avanadas que permitem facilitar o trabalho. No SSMS os "Registered Serveres" tem agrupamento natural pelo tipo de servidores isto Database Engine, Analysis Services, Reporting Services, SQL Server Compact e Integration Services, o que permite distinguir com facilidade os tipos de trabalho associado com cada um destes engines. Os "Registered Servers" tambm permitem fazer agrupamento de servidores (Server Group), que pode servir para agrupar os servidores pelo ambiente (Desenvolvimento, Qualidade, Testes e Produo) ou pela aplicao, tendo todos os ambientes respectivos como registos (SuperCalc, MegaMonitor, etc).
Uma funcionalidade muito avanada, mas ao mesmo tempo perigosa a capacidade de executar um query em todos os servidores registados de um agrupamento ou em todos os servidores registados naquele computador na totalidade. Essa funcionalidade deve ser utilizada pelos utilizadores muito experientes e sobretudo para tirar alguma informao diagnstica (e no pesada) sobre os respectivos servidores.
Para alm da maneira tradicional de efectuar uma ligao com a BD de SQL Server atravs da opo "Connect" do Object Explorer e introduzir o login e a password para cada servidor em separado para cada ligao, existe uma opo mais avanada que se chama "Registered Servers" e que permite configurar uma ligao apenas uma vez para utilizar mais tarde apenas com um "double click" e que inclui algu67
Para activar os "Registered Servers" basta abrir o men principal "View" e escolher a opo "Registered Servers" ou como alternativa utilizar a combinao de teclado "CTRL-ALTG". Logo aps a escolha desta opo vamos ter o seguinte view no ecr do nosso SSMS, onde poder consultar a lista de todos os servidores registados agrupados pelo Server Groups.
http://www.sqlport.com
Sempre podemos extrair a lista dos servidores registados para partilhar com novos colegas do nosso projecto, que conseguem importar o XML gerado pela ferramenta de exportao com muita facilidade. A importao do ficheiro XML com servidores registados um processo intuitivo: escolhe-se um grupo de servidores e faz-se click na tecla direita do rato e a seguinte escolha de opes Task->Import no menu contextual do SSMS. Basta escolher o ficheiro em questo e simplesmente clicar no OK para poder finalizar o processo tal como pode ver nas imagens ao lado deste texto.
No ecr de exportao de definies dos servidores registados existe uma opo para excluso do nome do utilizador e da password, para evitar os problemas de segurana, pois de uma boa prtica no geral manter utilizadores separados para cada membro da equipa. Mas por outro lado na altura de mudana de lugar de trabalho, a possibilidade de copiar os nossos servidores de trabalho uma funcionalidade que pode poupar imenso tempo. Nesta altura a migrao fica muito facilitada, pois no vamos precisar de criar todos os servidores e grupos de novo introduzindo as credenciais.
Para definio de um novo grupo de servidores registados basta clicar com a tecla direita do rato e escolher a opo com New Server Group que vai mostrar um novo dilogo para definio do nome e da descrio do grupo de servidores que estamos a definir. O processo por si fcil e no deve criar dificuldades a ningum que trabalha com uma ferramenta como SQL Server. A nica coisa estranha que para a edio do nome de grupo no existe nenhuma opo no menu contextual, pois a edio poder ser efectuada apenas atravs dos mtodos tradicionais de edio, como em Windows Explorer por exemplo 2 cliques com intervalo da tecla esquerda do rato ou como alternativa atravs da tecla F2.
68
http://www.sqlport.com
No ecr de definio de um novo servidor registado temos as opes habituais para escolha do nome de servidor, do tipo de autenticao, do nome de utilizador e da password se for necessrio e podemos definir o nome sobre qual o servidor vai aparecer na nossa lista, mais a descrio opcional que serve como um explicativo desta ligao.
A opo encrypt connection auto-explicatria e dever ser utilizada para aumentar a segurana, mas a opo custom color ainda no tem o reconhecimento que ela realmente merece: para definir uma cor customizada ns podemos assegurar o reconhecimento do tipo do ambiente onde estamos a trabalhar. Eu costumo definir 3 cores distintas para cada um dos ambientes de trabalho o verde para o ambiente de desenvolvimento, o amarelo para o ambiente de qualidade e o vermelho para produo. Ainda antes de gravar o nosso novo servidor registado, podemos sempre testar a nossa ligao atravs do boto Test para ter a certeza que todas as credenciais foram introduzidas correctamente.
Assim, aps estabelecimento de uma ligao a um servidor na parte baixa de janela dos queries teremos uma barra de cor definida para esta ligao, que assim nos vai servir de referncia e de aviso sobre o servidor com o qual estamos a trabalhar. Na definio de um novo servidor, para alm de opes General, temos um tab nomeado Connection Properties, que permite definir diversas opes de configurao, que Tendo uma barra vermelha em baixo qualquer um prestar mais ateno quilo que est a fazer, o que extremamente importante para o trabalho com servidores de ambiente de produo.
69
http://www.sqlport.com
Script Object As
Por vezes, durante o trabalho ns precisamos de consultar ou extrair um script completo de criao de um objecto de base de dados, como uma tabela por exemplo. Depois de criar uma tabela, se queremos pass-la para outro ambiente como QLD(Qualidade) ou PRD(Produo), ns podemos criar a tabela com o T-SQL e depois disponibilizar os ficheiros para os Database Administrators (DBAs). Mas o que que dever ser feito se a tabela em questo foi criada por uma outra pessoa que se esqueceu de guardar o script durante o procedimento de criao da Tabela? Acabamos sempre por precisar de scriptar a nossa Tabela, e para isso dentro de SSMS existe uma opo de criao de um script de T-SQL para um objecto.
As diversas opes que este menu contm incluem opes como a verso de SQL Server para qual o script dever ser gerado se tiver o SQL Server 2008 R2 instalado no PC onde estamos a trabalhar. Mas se o servidor com qual trabalhamos o SQL Server 2000, podemos simplesmente escolher a opo de SQL Server 2000 no General Scripting Options e o resultado final ser gerado tendo em conta o facto que o produto final ser utilizado no servidor de SQL Server 2000. As 2 opes Database Engine Type e Script for Server Version permitem adaptar o script para as necessidades do projecto entre SQL Server 2000 e at SQL Azure inclusive. Uma outra opo que eu escolho por defeito logo aps instalao de SSMS Include IF NOT EXISTS clause, que permite uma insero de um script que vai eliminar o objecto se ele no existir o que facilita imenso a passagem dos scripts como CREATE TABLE, assim tendo a certeza que caso um objecto com o nome da nossa tabela j exista, ele ser logo eliminado pelo script disponibilizado pela SSMS.
No exemplo que eu queria partilhar aqui, eu vou explorar a possibilidade de criar um script Transact-SQL (T-SQL) com criao de uma tabela para isto escolha-se um objecto no Object Explorer, fazemos o click com tecla direita do rato por cima deste objecto e escolhemos a opo Script Table as -> Create To e New Query Editor Window. Parece ser fcil, no verdade?Na verdade, por defeito aps instalao, a SSMS tem definies que no incluem alguns dos objectos associados nossa tabela no script gerado, o que leva muitos profissionais a dizerem que a SSMS est mal feita e que simplesmente no disponibiliza toda a informao necessria. Na verdade, a SSMS permite um controlo mais afinado de opes de exportao: podemos escolher nas opes quais objectos (triggers, constraints, statitistics, etc) vo ser includos na gerao do nosso script de T-SQL.
De resto eu deixo-vos explorar todas as diversas opes que existem neste menu, alertando para activar logo o scripting de objectos como Foreign Keys, Indexes, Unique Keys e Triggers por exemplo.
Resta apenas acrescentar uma pequena crtica, pois muitas destas opes deveriam ser muito mais acessveis para uma edio conforme as necessidades e no serem escondidas dentro de opes de SSMS.
RedGate SQL Search A famosa empresa inglesa de desenvolvimento de ferramentas para os Developers e DBAs, a RedGate disponibiliza gratuitamente uma das mais teis ferramentas para quem trabalha com SQL Server - RedGate SQL Search. 70
http://www.sqlport.com
uma lista com nomes de todas as bases de dados encontradas na instncia de SQL Server a qual estamos ligados, e onde para alm de escolher uma BD especfica podemos tambm optar por fazer a pesquisa em todas as bases de dados da instncia (Essa funcionalidade mesmo muito til para os DBA's)
A capacidade de procura de um contedo especfico sempre uma mais-valia, pois por exemplo no uso de motores de busca como Google ou Bing para um informtico, considero importante saber como limitar uma pesquisa dentro de um site especfico (syntax site:www.portugal-a-programar.org) ou conhecimento de aplicao de sintaxe mais bsico para excluir uma palavra de pesquisa (inciso do smbolo '-' antes de palavra).
A SQL Search integra-se dentro de SSMS num processo de instalao praticamente instantneo, e o toolbar da ferramenta consiste apenas num boto, que invoca o painel especial de ferramenta. A interface do SQLSearch muito simples e intuitiva, tendo apenas as seguintes opes:
uma textbox para introduzir os termos de pesquisa uma checkbox para especificar se a pesquisa dever ser
71
http://www.sqlport.com
O processo de pesquisa muito intuitivo e fcil - basta introduzir uma parte do nome do objecto pretendido e aps um click no "Enter", a SQL Search vai efectuar a pesquisa pelo texto pretendido entre os objectos do sistema, os textos de Stored Procedures, Functions, Triggers, etc
Algumas das funcionalidades que a SQL Search tem, estaro disponveis na prxima verso de SQL Server, nome de cdigo Denali, cuja FINAL RELEASE est a ser apontado para o final deste ou incio do prximo ano. O projecto "Juneau" que dever integrar a experincia de todos os profissionais que trabalham com SQL Server numa plataforma nica, baseada no Visual Studio - o projecto mais significativo dos ltimos anos para os Developers que trabalham com SQL Server.
O painel com resultados de pesquisa disponibiliza a funcionalidade extremamente til aps escolher o objecto encontrado, apenas com um double click poderemos ter este objecto aberto e focado no Object Explorer, o que na sequncia permitir a utilizao deste objecto tal como invocao ou edio de contedo no caso de uma stored procedure.
Nota: todos os screenshots foram tirados de verso SQL Server 2008 R2.
Recursos:
SQL Server 2008 R2 http://technet.microsoft.com/en-us/sqlserver/ff398089 RedGate SQLSearch: http://www.red-gate.com/products/sql-development/sqlsearch/ SQL Server Denali project Juneau: http://msdn.microsoft.com/data/tools
Escrito por Niko Neugebauer Actualmente um Snior Professional da Novabase, a maior empresa de informtica de Portugal. Possui uma experincia de 13 anos nas reas de desenvolvimento, desenho e arquitectura de Software. o fundador e o actual lder da comunidade portuguesa de SQL Server SQLPort (http://www.sqlport.com). Possui certificao MCITP em DEV de SQL Server 2005 e foi reconhecido pela Microsoft com a atribuio do ttulo MVP (Most valuable Professional). Twitter: @NikoNeugebauer
72
http://netponto.org
Instalao
O processo de instalao facilitado pelo NuGet: Install-Package fluentnhibernate Este comando, executado na consola de NuGet, instala o NHibernate juntamente com o FluentNHibernate 1.2 e as bibliotecas auxiliares das quais dependem. Este comando acrescenta as seguintes referncias a assemblies:
Neste artigo vamos usar uma biblioteca auxiliar chamada Fluent-NHibernate que trs uma API fluente que tenta ser mais intuitiva e que permita uma descoberta natural das funcionalidades disponveis conjuntamente com a possibilidade de configurar os mapeamentos de NHibernate de forma automtica, tirando partido de convenes definidas em cdigo que indicam qual a regra geral para mapear os objectos com tabelas. A verso de Nhibernate usada aqui a 3.1, com FluentNHibernate 1.2, ambos instalados atravs de NuGet (ferramenta para instalao e gesto automtica de pacotes criada pela Microsoft sob a gide da Outercurve Foundation).
Domnio
Vamos considerar para este artigo um domnio simples: uma edio com artigos e autores. Uma edio tem vrios artigos, um artigo tem vrios autores:
Como base de dados vamos usar SQLite, atravs da biblioteca System.Data.SQLite. Desta forma no necessrio instalar e configurar uma base de dados para correr o cdigo deste artigo. Visto o NHibernate fornecer abstraes sobre a base de dados, todo o cdigo deste artigo funciona da mesma forma para outros motores de bases de dados, sendo apenas necessrio mudar o driver de ligao base de dados e a respectiva connection string. A instalao deste pacote igualmente fcil utilizando o NuGet: Install-Package System.Data.Sqlite
namespace Portugal_A_Programar.Entidades { public class Edicao { public DateTime DataEdicao { get; set; } public Artigo TemaDeCapa { get; set; } public IList<Artigo> Artigos { get; set; } } public class Artigo { public string Titulo { get; set; } public ISet<Autor> Autores { get; set; } } public class Autor { public string Nome { get; set; } public string Email { get; set; } public ISet<Artigo> Artigos { get; set; } } }
Configurao
A configurao feita fluentemente atravs do interface comeado por Fluently.Configure:
var sessionFactory = Fluently.Configure() .Database(SQLiteConfiguration.Standard .ConnectionString("Data Source=database.sqlite")) .Mappings(mapping => mapping.AutoMappings. Add(AutoMap.AssemblyOf<Edicao>() .Where(t => t.Namespace.EndsWith("Entidades")))) .ExposeConfiguration(configuration => new SchemaUpdate(configuration) .Execute(false, true)) .BuildSessionFactory();
74
http://netponto.org
Configurao da ligao base de dados No cdigo anterior estamos a indicar com o mtodo .Database que nos queremos ligar a uma base de dados Standard de SQLite, com a Connection String indicada. No entanto para ligar a uma base de dados SQLServer 2008 to simples quanto substituir a referncia ao SQLLite por:
Exposio da configurao Caso seja necessrio usar directamente o objecto de configurao de NHibernate possvel obt-lo atravs do mtodo .ExposeConfiguration. Como a configurao apenas concretizada no momento de instanciao da ISessionFactory na chamada ao mtodo de .BuildSessionFactory, para poder aceder configurao passada uma Action<Configuration> que recebe a configurao construda por FluentNHibernate e actua sobre a mesma. Neste caso estamos a construir uma instncia da classe SchemaUpdate que acede base de dados configurada, inspeciona as tabelas e colunas existentes, os mapeamentos definidos e executa os comandos necessrios para que a base de dados corresponda ao mapeamento, o que inclui criar tabelas e acrescentar colunas. No entanto, com esta configurao no so realizadas alteraes destrutivas como remover colunas ou tabelas. Desta forma conseguimos evoluir o desenvolvimento inicial de uma forma mais clere deixando a sincronizao da base de dados com o modelo de objectos para esta ferramenta e, numa fase posterior, gerir manualmente o esquema de base de dados.
MsSqlConfiguration.MsSql2008.ConnectionString (connectionString) Tambm possvel aqui configurar outros parmetros da base de dados atravs dos mtodos disponibilizados pelo configurador, nomeadamente o tamanho do batch de ADO.NET. Existem configuradores para as mais variadas bases de dados, sendo que possvel sempre construir um atravs da implementao do interface IPersistenceConfigurer
Configurao dos mapeamentos Com o mtodo Mappings possvel configurar a forma como NHibernate faz o mapeamento entre as classes existentes no programa e o esquema de tabelas da base de dados. Neste caso estamos a indicar que queremos mapear automaticamente todas as classes da Assembly da classe Edio cujo namespace acabe em Entidades com as convenes que esto configuradas por omisso. Com FluentNHibernate existem 3 tipos de mapeamentos:
Primeiro uso
Se tentarmos executar o cdigo de configurao j apresentado, observamos que ele falha com a seguinte excepo: Unhandled Exception: FluentNHiberna te.Cfg.FluentConfigurationException: An invalid or incomplete configuration was used while creating a SessionFactory. Check PotentialReasons collection, and InnerException for more detail. A InnerException contm o motivo do erro: ---> FluentNHibernate.Visitors.ValidationException:
Estes trs tipos de mapeamento esto disponveis nos trs membros da instncia que passada na funo .Mappings : mapping.FluentMappings, mapping.AutoMappings e mapping.HbmMappings. Mapeamentos fluentes permitem declarar em cdigo para cada classe a forma como esta se mapeia com a base de dados (incluindo relaes, identificadores, colunas e tabe75
http://netponto.org
Convenes e Overrides
No nosso exemplo estamos a usar mapeamentos automticos. Como tal, h duas formas principais de indicar os mapeamentos: atravs de regras gerais aplicadas a todas/ algumas classes mapeadas (convenes) ou atravs de indicaes especficas para um tipo de mapeamento indicado (overrides)
Convenes Para este caso vamos definir a conveno de que os identificadores so sempre membros com o nome Id, do tipo inteiros, e gerados no cliente com o mecanismo HiLo.
Identity a forma tradicional, em que a base de dados gera um identificador para cada linha introduzida numa tabela. Implica que de cada vez que se persiste uma nova entidade seja necessrio um round-trip base de dados para saber qual o identificador, por oposio a apenas ser feito um round-trip quando se faz commit da transaco. HiLo o esquema actualmente recomendado na grande maioria dos casos. Cada cliente (na realidade cada instancia de ISessionFactory), quando precisar de um identificador, reserva na base de dados os prximos N identificadores a serem atribudos s entidades que vo ser gravadas. Desta forma, possvel gerir os identificadores em batch do lado do cliente, mantendo-se no entanto a unicidade dos mesmos. comum observar-se uma subida rpida dos identificadores que usam este esquema durante a fase de desenvolvimento, com largos espaos entre identificadores, porque de cada vez que instanciada uma ISessionFactory reservada mais uma sequncia de elementos. No entanto, quando o sistema se encontra em produo isto j no se verifica, visto uma ISessionFactory ter um ciclo de vida to longo quanto a aplicao e, como tal, no to comum reservar sequncias sem as usar. No entanto, caso seja necessrio, sempre possvel alterar o nmero de identificadores reservados por cada instncia, que tem de ser igual entre todas as instncias concorrentes. Guid so os tradicionais identificadores nicos que so gerados do lado do cliente. No entanto, devido a aleatoriedade dos mesmos, tipicamente origina uma elevada fragmentao na base de dados. Nesse caso possvel recorrer a Comb, um esquema alternativo que gera identificadores de forma mais sequencial, reduzindo, assim, a fragmentao na base de dados. Finalmente, um identificador pode ser do tipo Assigned quando ele gerido pelo cdigo cliente da biblioteca, como 76
public class IdsConvention : IIdConvention { public void Apply(IIdentityInstance instance) { instance.Column("Id"); instance.GeneratedBy.HiLo("HiLo", "Hi", "100"); } } Neste caso estamos a indicar a coluna "Hi" da tabela "HiLo" que ser uma tabela na base de dados utilizada para armazenar as sequncias, com um valor de 100 para o nmero de identificadores reservados por ISessionFactory. Todas as convenes existentes tm como interface base IConvention, sendo possvel explor-las no namespace FluentNHibernate.Conventions. Caso a conveno apenas se deva aplicar a parte das entidades mapeadas, existem os interfaces que herdam de IConventionAcceptance<TInspector>, tipicamente um para cada conveno, que definem um mtodo que indica se para a parte inspecionada ir ser aplicada a conveno respectiva.
Overrides No entanto, para o caso da Edicao, vamos fazer um override s convencesconvenes e indicar que o identificador o membro DataEdicao, do tipo datetime, e que ser atribuidoatribudo por ns, visto ser uma chave natural. public class EdicaoOverride : IAutoMappingOverride<Edicao> { public void Override(AutoMapping<Edicao> mapping) { mapping.Id(edicao => edicao.DataEdicao) .Column("DataEdicao") .GeneratedBy.Assigned(); }}
http://netponto.org
Alteraes as classes e nova verso da inicializao Para tal vamos alterar as classes Artigo e Autor da seguinte forma:
A classe Edicao no necessita de ser alterada, uma vez que a sua chave definida de forma especfica e a propriedade DataEdicao j existe.
public class Artigo { public int Id { get; set; } public string Titulo { get; set; } public ISet<Autor> Autores { get; set; } } public class Autor { public int Id { get; set; } public string Nome { get; set; } public string Email { get; set; } }
Para o FluentNHibernate aplicar as convenes e overrides preciso alterar a chamada ao mtodo .Mappings do seguinte modo:
.Mappings(mapping => mapping.AutoMappings .Add(AutoMap.AssemblyOf<Edicao>() .Where(t => t.Namespace.EndsWith("Entidades")) .Conventions.AddFromAssemblyOf<IdsConvention>() .UseOverridesFromAssemblyOf<EdicaoOverride>())) Aqui indicamos que queremos usar todas as convenes existentes na assembly da classe IdsConvention, e os overrides da assembly da classe EdicaoOverride. Deste modo, o FluentNHibernate procura automaticamente os tipos pblicos dentro das assemblies e usa-os para configurao. Aps estas alteraes estamos prontos para tentar correr o cdigo outra vez. Ao correr esta verso deparamo-nos com mais uma FluentConfigurationException: The following types may not be used as proxies: artigo_1.nhibernate.Entidades.Artigo: method get_Id should be 'public/protected virtual' or 'protected inter nal virtual' artigo_1.nhibernate.Entidades.Artigo: method set_Id should be 'public/protected virtual' or 'protected internal virtual' (...) Neste caso, tal como podemos observar na excepo, ele queixa-se de que as propriedades das classes mapeadas 77
Coleces em NHibernate Podem reparar que as classes esto criadas no com List mas sim com IList e ISet. Depois da discusso relativa ao lazy-loading e proxies torna-se mais facilmente compreensvel esta escolha. Quando um objecto carregado, por omisso apenas car-
http://netponto.org
Uma List (lista) tem o comportamento de uma lista ordenada e mapeada como IList. Um Map (mapa) um conjunto de pares chave, valor e mapeado como IDictionary. Um Set (conjunto) um conjunto no ordenado que permite repeties, mapeado como ISet (no um tipo nativo sendo que est disponvel na biblioteca Iesi.Collections). Um Bag (saco), como um Set um conjunto no ordenado de entidades que permite repeties. No existe um interface especfico para este tipo de coleco, sendo que pode ser mapeado para IList ou ICollection.
O comportamento tpico das coleces em aplicaes mapeia-se em conjuntos, visto a ordem no ser relevante. Caso a ordem seja relevante, deve mapear-se como uma lista e indicar qual a coluna que guarda o ndice que define a posio do item na lista.
Alteraes s entidades e aos mapeamentos Agora que j temos uma melhor compreenso do modo de funcionar de mapeamentos e coleces, vamos alterar as nossas entidades para passarem a ter todas as propriedades como virtual: public class Edicao { public virtual DateTime DataEdicao { get; set; } public virtual Artigo TemaDeCapa { get; set; } public virtual IList<Artigo> Artigos { get; set; } } public class Artigo { public virtual int Id { get; set; } public virtual string Titulo { get; set; } public virtual ISet<Autor> Autores { get; set; } } public class Autor { public virtual int Id { get; set; } public virtual string Nome { get; set; } public virtual string Email { get; set; } public virtual ISet<Artigo> Artigos { get; set; } } Uma lista, ao contrrio de um saco, uma sequncia ordenada de elementos. Como tal, precisamos de indicar ao NHibernate qual a coluna que guarda o ndice de cada elemento
Criar e gravar objectos Para interagir com a base de dados NHibernate implementa 78
http://netponto.org
http://netponto.org
Carregar uma entidade Agora que j temos dados na base de dados, vamos querer comear a ir busca-los. O caso mais simples carregar uma edio pela chave:
Cascades Quando duas entidades esto relacionadas, como o caso de Edicao e Artigo, comum o ciclo de vida das mesmas tambm estar relacionado. Quando se adiciona ou altera um artigo de uma edio e se grava, pretende-se que o artigo seja tambm gravado, visto estar associado edio. Para responder a este requisito existe a funcionalidade de Cascade, semelhante ao Cascade de SQL, mas que funciona de forma independente do mesmo, sendo que em NHibernate existem as seguintes opes:
O NHibernate vai buscar o objecto base de dados, sendo que retorna null no caso em que o mesmo no exista. No entanto, existe outra forma de carregar dados por chave:
save-update - quando o objecto adicionado ou actualizado, as associaes marcadas com este cascade so verificadas e gravadas ou adicionadas caso seja necessrio Com o mtodo .Load ele retorna um proxy do objecto que apenas resulta num hit base de dados, se for necessrio (tal como discutimos para o lazy-loading de coleces). Isto quer dizer que no seguinte exemplo no efectuado nenhum select, visto no ser necessrio para atribuir o identificador ao .TemaDeCapa: new Edicao { DataEdicao = new DateTime(2011, 07, 01), TemaDeCapa = session.Load<Artigo>(1) }; No entanto preciso ter a certeza que o identificador existe, caso contrrio lanada uma excepo quando se tenta aceder ao campo ou se tenta gravar na base de dados (no caso de relaes com chaves estrangeiras).
Queries O NHibernate tem vrias formas de efectuar queries base de dados: 1) Atravs de Linq:
IList<Edicao> edicoesDe2011 = session.Query<Edicao>() .Where(e => e.DataEdicao >= new DateTime(2011, 1, 1) && e.DataEdicao < new DateTime(2012, 1, 1)) .ToList();
http://netponto.org
var edicoesDe2011 = session.CreateQuery( "from Edicao where DataEdicao >= :EsteAno and DataEdicao < :ProximoAno") .SetDateTime("EsteAno", new DateTime(2011, 1, 1)) .SetDateTime("ProximoAno", new DateTime(2012, 1, 1)) .List<Edicao>();
Esta uma forma nativa e bastante poderosa - que existe desde as primeiras verses do NHibernate, para fazer queries sobre objectos persistidos com uma sintaxe semelhante a SQL. Este mecanismo, embora poderoso, no facilita a composio de queries, por serem strings. Pela mesma razo no aproveita as funcionalidades de C# ou VB para apoiar os programadores atravs de auto-complete e verificaes em tempo de compilao. 3) A terceira hiptese a utilizao de ICriteria:
var edicoesDe2011 = session.CreateSQLQuery( @" select edicao.DataEdicao from Edicao edicao where DataEdicao >= :EsteAno and DataEdicao < :ProximoAno") .SetDateTime("EsteAno", new DateTime(2011, 1, 1)) .SetDateTime("ProximoAno", new DateTime(2012, 1, 1)) .SetResultTransformer (Transformers.AliasToBean<Edicao>()) .List<Edicao>();
var edicoesDe2011 = session.CreateCriteria<Edicao> () .Add(Restrictions.Ge("DataEdicao", new DateTime(2011, 1, 1))) .Add(Restrictions.Lt("DataEdicao", new DateTime(2012, 1, 1))) .List<Edicao>(); Esta soluo igualmente expressiva, sendo que a principal vantagem face a HQL a sua flexibilidade para composio de partes das queries, reduzindo a duplicao de cdigo e possibilitando a criao de algumas abstraes de negcio sobre as queries. No entanto continua a utilizar strings para identificar as propriedades das entidades, o que propicia erros no s quando se escrevem queries, mas tambm devido a esquecimentos aquando de refactorizaes. 4) A hiptese mais recente chama-se de QueryOver e junta a expressividade de ICriteria tipicao de Linq: var edicoesDe2011 = session.QueryOver<Edicao>() .Where(e => e.DataEdicao >= new DateTime(2011, 1, 1) && e.DataEdicao < new DateTime(2012, 1, 1)) .List();
Aqui preciso ter em ateno forma como os dados que vm da base de dados so interpretados pelo NHibernate. Como se est a construir simplesmente um query sq, o NHibernate no sabe priori qual o mapeamento entre colunas e propriedades ou classes, pelo que precisamos de lhe indicar como deve interpretar que os objectos vo ser interpretados. Neste exemplo estamos a ir buscar apenas o Id da edio e usamos um ResultTransformer chamado AliasToBean que olha para as colunas que vm no resultado da query e mapeia-se como propriedades do tipo de objecto que lhe passado. Assim, as instncias resultantes no so entidades completamente hidratadas mas sim simples DTOs ou ViewModels, usados em casos de leitura de dados com queries optimizadas.
Queries mais avanadas Nos exemplos mostrados na seco anterior realizmos queries simples que apenas operam sobre a entidade. No entanto igualmente possvel operar sobre mais do que uma entidade, percorrendo as coleces atravs de joins. Vejamos o seguinte exemplo, que retorna todas edies cujo tema de capa inclui a palavra "Basic":
81
http://netponto.org
No entanto, ao executarmos este query sobre os dados criados previamente, iramos encontrar resultados duplicados na lista retornada. Se executarmos o query de sql directamente na base de dados o motivo torna-se mais claro, visto o query retornar duas linhas com a mesma entidade, e o NHibernate no saber se a duplicao intencional. Uma hiptese usar o transformador Transformers.DistinctRootEntity, que desduplica as entidades quando interpreta os resultados vindos da base de dados. No entanto esta soluo encontra problemas quando usada em conjunto com paginao. Como as linhas na base de dados se encontram duplicadas e os limites esto a contabilizar as mesmas duplicaes, ao ser feito um pedido de 10 itens acabamos por poder ter menos itemsitens na lista resultante, um pedido de 10 itens pode vir com menos. Por todos estes motivos, a soluo mais correcta passa por passar a condio para uma subquery (o que permite aplicar limites sobre as linhas das entidades raiz):
Artigo artigo = null; Autor autor = null; var edicoesComArtigosDoManuel = session.QueryOver<Edicao>() .JoinQueryOver(edicao => edicao.Artigos, () => artigo) .JoinQueryOver(() => artigo.Autores, () => autor) .Where(() => autor.Nome == "Manuel") .List(); Aqui para alm dos .JoinQueryOver temos tambm duas variveis inicializadas a null e usadas apenas em expresses lambda. Esta a forma usada pelo mecanismo QueryOver para declarar nomes para cada uma das colees referenciadas pelos joins. As variveis artigo e autor apenas servem como mnemnicas, e no so usadas na execuo do cdigo. Caso precisemos de declarar outros tipos de join, podemos prefixar a chamada ao mtodo com Inner, Left ou Right (Inner.JoinQueryOver(() => artigo.Autores) por exemplo). O SQL gerado no revela nenhuma surpresa: SELECT this_.DataEdicao as DataEdicao3_2_, this_.TemaDeCapa_id as TemaDeCapa2_3_2_, artigo1_.Id as Id0_0_, artigo1_.Titulo as Titulo0_0_, autores5_.Artigo_id as Artigo1_, autor2_.Id as Autor2_, autor2_.Id as Id2_1_, autor2_.Nome as Nome2_1_, autor2_.Email as Email2_1_ FROM "Edicao" this_ 82
Artigo artigo = null; Autor autor = null; var edicoesComArtigosDoManuel = session.QueryOver<Edicao>() .WithSubquery.WhereProperty(edicao => edicao.DataEdicao) .In(QueryOver.Of<Edicao>() .JoinQueryOver(a => a.Artigos, () => artigo) .JoinQueryOver(() => artigo.Autores, () => autor) .Where(() => autor.Nome == "Manuel") .Select(a => a.DataEdicao)) .TransformUsing (Transformers.DistinctRootEntity) .List();
Aqui a condio existe na subquery, evitando-se assim resultados duplicados na query principal, que retornada.
Para definir subqueries usam-se DetachedQueryOver (existindo um correspondente DetachedCriteria por baixo desta implementao), que so criados para uma entidade atravs do mtodo QueryOver.Of. O builder devolvido por este mtodo tem um comportamento idntico ao QueryOver da ISession, com a diferena de que lida com queries no ligadas a nenhuma sesso (dai o nome de detached). Estas
http://netponto.org
Existem ainda bastantes tpicos que ficam por abordar, tais como eager loading, projeces, interceptors, entre outros que sero abordados nos prximos artigos.
Referncias
http://www.nhforge.org/ - NHForge site oficial da comunidade de Nhibernate: http://knol.google.com/k/fabio-maulo/ nhibernate/1nr4enxv3dpeq/21# - Knol do FabioFbio Maolo sobre NHibernate http://fluentnhibernate.org/ - Site da biblioteca FluentNHiberna
Escrito por Bruno Lopes Bruno Lopes fez o curso de Engenharia Informtica no IST, e neste momento conta com mais de 5 anos de experincia profissional em IT, em particular nas reas de desenvolvimento de software web-based. Actualmente co-fundador da weListen Business Solutions, trabalhando no produto InnovationCast, e participa activamente na comunidade NetPonto, apresentando temas como NHibernate, RavenDB ou IoC. Tem blog em http://blog.brunomlopes.com, twitter em @brunomlopes e linkedin em http://pt.linkedin.com/in/brunomlopes
83
http://www.sharepointpt.org
Com o lanamento na Microsoft da sua soluo Cloud atravs do Office 365 tem havido muita procura sobre as diferentes ofertas que este novo servio disponibiliza. Office 365 um conjunto de Servios da Microsoft na qual se pode aceder em qualquer local a documentos, correio electrnico, contactos, calendrios de forma actualizada, tendo como garantia a fiabilidade e segurana a nvel empresarial de forma a disponibilizar a pequenas e grandes empresas com um conjunto de servios essenciais de trabalho a um preo acessvel.
Aps o lanamento da verso Beta do Office 365 um dos produtos no qual foquei a minha ateno foi o SharePoint Online 2010 e a capacidade de criar Sandbox Solutions. Sandbox Solutions em SharePoint um novo conceito para SharePoint 2010 que permite criar cdigo personalizado a aplicar nos sites de SharePoint de forma segura, fornece a capacidade dos Site Collections Administrator de instalar e monitorizar solues personalizadas sem a necessidade dos Administradores do SharePoint. Mas para ter essa liberdade os Administradores esto limitados as funcionalidades das Sandboxed Solutions, relativo ao cdigo que podem utilizar ou os recursos que podem utilizar/aceder. A diferena das Sandbox Solution para Solues em Farm a camada de acesso as diferentes Assembleis e nveis de permisso para sua infraestrutura enquanto as Sandbox Solutions encontram-se muito limitadas a camada dos Sites e Webs, as Farm Solutions fornece um acesso alargado ao contedo da infra-estrutura no SharePoint 2010 que vo desde aos servios das Farm as das Web Application .
What Can Be Implemented in Sandboxed Solutions in SharePoint 2010 http://msdn.microsoft.com/en-us/library/gg615464.aspx Restrictions on Sandboxed Solutions in SharePoint 2010 http://msdn.microsoft.com/en-us/library/gg615454.aspx Microsoft.SharePoint.dll APIs That Are Available from Sandboxed Solutions http://msdn.microsoft.com/en-us/library/ee537860.aspx
http://www.sharepointpt.org
Templates para Visual Studio 2010 de apoio para a criao deste exemplo: Visual Studio 2010 SharePoint Power Tools http://visualstudiogallery.msdn.microsoft.com/8e602a8c-6714 -4549-9e95-f3700344b0d9/ CKS: Development Tools Edition http://cksdev.codeplex.com/ SharePoint 2010 Extensibility Projects http://archive.msdn.microsoft.com/vsixforsp
O template fornece a capacidade de visualizar os componentes ASP.Net num User Control onde ser desenhada a nossa WebPart.
Criar uma nova soluo no Visual Studio 2010 e criar novo Projecto para SharePoint 2010, aps novo Projecto definir Empty project e definir no SharePoint Wizard a opo Deploy as a Sandboxed Solution, esta opo ir validar a soluo a criar para as Sandbox Solutions.
MasterPages
Neste exemplo foi criado uma nova componente para alterar a MasterPage e aplicar como default assim que o componente for activo.
85
http://www.sharepointpt.org
Custom Actions
A funcionalidade tem como aco demostrar como o Module Elements foi alterado para adicionar novas aces nos menus das List item atravs da utilizao de Content Types. SharePoint constitudo por Content Types, estes Content Types ajudam a definir a Metadata associada a cada Tipo de Listas, seleccionado a propriedade e a sua interdependncia entre os diversos Content Types que esto constitudos na lista. Este Custom action tem como funo definir uma aco que seja visvel em qualquer tipo de Lista para isso foi definido o Content Type Item onde todos os Content Types para listas derivam. Exemplo: http://grounding.co.za/blogs/brett/archive/2008/09/09/ sharepoint-content-type-id-s.aspx
SharePoint Ribbons
A funcionalidade tem como aco demostrar como o Template Server Ribbon pode ser utilizado para personalizar o controlo de Ribbon para SharePoint 2010. Este template disponibiliza um conjunto de customizaes pr-definidas para a criao do Ribbons em SharePoint 2010 de uma forma simples.
86
http://www.sharepointpt.org
List Definition
Esta funcionalidade ira criar uma nova Lista com campo Title, esta lista poder ser utilizada ou alterada para registar os erros criadas pelo cdigo das features em sandbox.
87
http://www.sharepointpt.org
Sandbox Ribbons
Para visualizar as novas opes da soluo RibbonSandbox devemos seleccionar uma Lista de Links no SharePoint Online, ai ira aparecer uma nova Tab com o nome Sandbox, ao seleccionar aparece um grupo chamado Custom Sandbox com duas novas opes que ira despoletar aces de mensagem.
List Definition
Para visualizar as novas opes da soluo RibbonSandbox 88
http://www.sharepointpt.org
Actualmente, no possvel implantar solues directamente do Visual Studio 2010 para o SharePoint Online. Mas posso recomendar utilizar um Site de SharePoint 2010 on-premise com a Sandbox desenvolvida, esta tambm ir ser aceite no SharePoint Online.
Este um pequeno exemplo sobre como criar Sandbox Solution utilizando os diversos Templates disponibilizados para o Visual Studio 2010. Espero que tenham gostado, at a prxima
Existem muitos outros componentes que podem ser utilizados na criao das nossas Sandbox Solution aqui ficam uma lista a usar. What Can Be Implemented in Sandboxed Solutions in SharePoint 2010 http://msdn.microsoft.com/en-us/library/gg615464.aspx
Links utilizados como referncia para este artigo: Microsoft Office 365 http://www.microsoft.com/pt-pt/office365 Developing, Deploying, and Monitoring Sandboxed Solutions in SharePoint 2010 http://msdn.microsoft.com/en-us/magazine/ee335711.aspx Developing for SharePoint Online with Sandbox Solutions http://msdn.microsoft.com/en-us/hh181574 Sandboxed Solutions Architecture in SharePoint 2010 http://msdn.microsoft.com/en-us/library/ee539417.aspx What Can Be Implemented in Sandboxed Solutions in SharePoint 2010 http://msdn.microsoft.com/en-us/library/gg615464.aspx Restrictions on Sandboxed Solutions in SharePoint 2010 http://msdn.microsoft.com/en-us/library/gg615454.aspx Add Actions to the User Interface http://msdn.microsoft.com/en-us/library/ms473643 (v=office.12).aspx
Dicas:
Criar uma Lista chamada Logs onde ira ficar registados todos os erros despoletados pelo Web Part ou outras funcionalidades associadas as Sandbox, as classes WriteTrace e SPDiagnosticsCategory no podem ser utilizadas em Sandbox devido a limitao do Scope ao Site do SharePoint Online. Validao do cdigo atravs de Ferramentas prprias como MICROSOFT SHAREPOINT ONLINE CODE ANALYSIS FRAMEWORK (MSOCAF). Leitura documentao da Microsoft associada a Office 365 http://www.microsoft.com/download/en/details.aspx? id=17069 http://www.microsoft.com/download/en/details.aspx? id=14889
Escrito por Andr Lage Microsoft SharePoint MVP, trabalhando na Sua em empresa Farmacutica e Banca. Apoiando as diversas Comunidades em SharePoint pelo mundo com participaes em eventos como speaker e efectuando artigos com focos nas tecnologias SharePoint. Um dos administradores da Comunidade Portuguesa de SharePoint, Co-fundada por Rodrigo Pinto, www.Sharepointpt.org. Blog pessoal http://aaclage.blogspot.com/
89