domingo, 29 de abril de 2012

Scala com Spring: a primeira impressão


Spring, como é sabido pelos desenvolvedores Java, é um framework escrito na linguagem Java e muito poderoso, estável e cujas funcionalidades auxiliam os programadores a escrever menos código. 
Assim, como é possível fazer programas desenvolvidos em Scala interoperarem com programas desenvolvidos em Java, então também é possível construir uma aplicação em Scala totalmente integrada com Spring. Para tanto existem algumas observações, que precisam ser consideradas. O objetivo aqui não é discutir se isto é ou não viável, mas sim como fazer isto de forma simples e mantendo a experiência do desenvolvedor.

Para começar vamos considerar uma Entidade chamada de Order que deverá ser mantida em um banco de dados PostgreSQL. Supondo que você tenha um Projeto Scala preparado com todas as bibliotecas e dependências do Spring (cujos JARs estão em lib), o arquivo de configuração terá o seguinte conteúdo:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">

<!-- DataSource -->
<bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.postgresql.Driver" />
<property name="url" value="jdbc:postgresql://localhost:5432/db_scala" />
<property name="username" value="postgres" />
<property name="password" value="123456" />
</bean>
<!-- Hibernate Configuration-->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="datasource" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.use_sql_comments">false</prop>
</props>
</property>
<property name="annotatedClasses">
<array>
<value>...</value>
</array>
</property>
</bean>
<!-- Transaction management -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager" >
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- Instruct Spring to perform declarative transaction management automatically on annotated classes. -->
<tx:annotation-driven transaction-manager="transactionManager" mode="proxy"  />

</beans>



O objeto que repesentará o pedido "Order" terá uma identidade que em outro momento utilizaremos como EmbededId. Por enquanto basta termos:

/** 
  * Representa a identidade de uma entidade
  */
case class Identity(companyId:String, domObjId: String)

/**
  * Pedido
  */
@Entity
case class Order(identity:Identity){
  @Id
  private var id = identity.domObjId
}


Para realizar as operações de CRUD, construíremos um DAO (Data Access Object pattern), o qual terá o seguinte conteúdo:

class OrderRepositoryImpl(sf:SessionFactory) {
  private val hibernate:HibernateTemplate = new HibernateTemplate(sf)
  
  def save(obj:Order){
    hibernate.saveOrUpdate(obj)
  }
  
  def remove(obj:Order){
    hibernate.execute(new HibernateCallback[Unit](){
      override def doInHibernate(session:Session) = {
        val query = session.createQuery("delete from Order o where o.companyid = :companyid and o.code = :code")
        query.setParameter("companyid", obj.identity.companyId)
        query.setParameter("code", obj.identity.domObjId)
        query.executeUpdate()
      }
    })
  }
  
  def removeAll(){
    hibernate.execute(new HibernateCallback[Unit](){
      override def doInHibernate(session:Session){
        val query = session.createQuery("delete from Order")
        query.executeUpdate()
      }
    })
  }
  def find(id:Identity):Order = {
    hibernate.execute(new HibernateCallback[Order](){
      override def doInHibernate(session:Session):Order = {
        val query = session.createQuery("select o from Order o where o.companyid = :companyid and o.code = :code")
        query.setParameter("companyid", id.companyId)
        query.setParameter("code", id.domObjId)
        query.uniqueResult().asInstanceOf[Order]
      }
    })
  }
 
  def findByCriteria(criteria: Criteria):List[Order] = {
   import scala.collection.JavaConversions._
    hibernate.execute(new HibernateCallback[List[Order]](){
      override def doInHibernate(session:Session):List[Order] = {
        val c = DetachedCriteria
        .forClass(Order.getClass())
        .getExecutableCriteria(session)
        c.list().asInstanceOf[List[Order]]
      }
    })
  } 
  
}


Algumas observações, aqui já para iniciar: 
1) Scala possui Collections próprias, sendo que o Spring trabalho com as Collections do Java. Para compatibilizar é necessário importar a seguinte biblioteca:
import scala.collection.JavaConversions._

2) O session factory será passado pelo construtor no Spring, portanto a :
class OrderRepositoryImpl(sf:SessionFactory) {...

Com estas operações definidas será possível realizar o nosso CRUD sobre Order utilizando OrderRepositoryImpl cujo SessionFactory será injetado pelo Spring. Mas não para por ai. Para realizar os testes será utilizado o ScalaTest Framework. E o conteúdo do caso de teste será:


class OrderTest extends FunSuite {
  
  var i = new Identity("co0001", "or0001")
  var o = new Order(i)
  
  test ("salvar o pedido") {  
    //na pasta src dentro de META-INF, encontra-se o arquivo de configuração do spring
    val context = new ClassPathXmlApplicationContext("META-INF/ag-shoppingmanager-core.xml")
    val bean = context.getBean("orderRepository")

    //verificação antes da remoção
    bean.asInstanceOf[OrderRepositoryImpl].save(o)

    //verificação antes da remoção
    val e = bean.asInstanceOf[OrderRepositoryImpl].find(i)

    //teste
    assert(e != null)
  }
  
...

}

object OrderTestMain {
  def main(args: Array[String]) {
 Runner.main(Array[String]("-p", "scalatest-1.7.2-tests.jar", "-o", "-s",  "br.com.arigarcia.shoppingmanager.core.OrderTest"));
  }
}




Pronto...  realizado o teste você poderá verificar que os testes se sairão perfeitamente. Mas como foi dito no inicio segue algumas observações:
1) A utilização de List (do Scala) poderá criar uma complexidade sem nenhuma vantagem;
2) As anotações de @Id e @Column só podem ser feitas diretamente nos atributos e não em parametros, logo não será possível utilizar um construtor personalizado para a entidade no Scala de uma forma mais elegante, sendo necessário a redundância de dados, ou, se optar por remover o construtor personalizado, construir um "ScalaBean" (similar ao JavaBean, para a linguagem Java).
3) Os atributos que possuem Enumerations devem ser repensados para serem convertidos em String manualmente ou então terá que construir um conversor implicito personalizado para resolver este problema.

Por enquanto é só! Com certeza terá mais problemas... a questão é avaliar qual o benefício de interoperar estas aplicações: 
- O que o Scala faz que Java não faz?
- Em que realmente o Scala é melhor que Java?
- Compensa estudar tanta complexidade para simplesmente utilizar Scala ou é melhor utilizar Java?

Existem outros problemas no que se refere a produtividade, não por causa da linguagem em si, mas por causa da falta de ferramente que auxilie a encontrar problemas mais rapidamente (o eclipse ainda está muito imaturo, mas é o mais maduro dentre os que testes - netbeans, intelij, emacs, e mais outras 2 que não lembro o nome agora).

Até o final desse projeto passarei mais informações sobre desenvolvimento com Scala.


Até lá!




segunda-feira, 23 de abril de 2012

Scala: conversões implicitas

Hoje em discussão com colegas aqui na empresa percebi que existe algo interessante na linguagem Scala que merece ser citado, aproveitando o raciocínio de ontem: a Conversão Implicita.

A melhor forma de apresentar isto é fazendo uma demonstração. Então criamos duas classes que se referem ao tipo geral, automóvel (conceitualmente), porém não correlacionadas diretamente (através herança, por exemplo), logo é de se supor que seja possível criar algo do tipo:

def fiatUnoMy(b:FiatUno){
    ...
    println(b.my())
}

onde, 

class Automovel() {
  val name = "FiatUno"
  def my():String = "Is my FiatUno"
}

class FiatUno(name:String) {
  def getName() = name
}

Bem... então a primeira vista algum pode até imaginar que a linguagem é possui alguma inteligência ou que o método my() é um membro de qualquer classe. Porém, nenhum destes pensamentos é verídico. Esse fato expetacular ocorre porque o FiatUno é convertido implicitamente em um Automóvel. Como? Ai está o legal da história! Utilizando-se do mecanismo de "Implicit Convertion". Explicando em miudos: através deste mecanismo é possivel ter uma classe A (de automóvel) que possui um método x, cuja instrução A.x é possível. Uma outra classe, independente de A, chamada de F (de fiat uno), não poderá, então realizar a operação F.x, dado que x mão é um membro de F. Para isto é necessário transformar A em F, ou seja, tornar A = T(F) . E isto é feito através de uma função chamada implicitamente pelo compilador, levando a situação T(F).x.  Será que este assunto não é familiar para você? (para quem estudou Algebra, com certeza!). Em Scala, esta transformação é feita da seguinte maneira:

  ...
  implicit def convertToAutomovel(f: FiatUno) = new Automovel()
  implicit def convertToFiatUno(a: Automovel) = new FiatUno("New Fiat Uno")  
  ...

Com isto é possível termos:

def fiatUnoMy(b:FiatUno){
    println(b.getName)// print: New Fiat Uno
    println(b.name)//print: Fiat Uno
    println(b.my())//print: Is my FiatUno
}

Isto é show demais!!
Bem, por agora é só! Até a próxima.


domingo, 22 de abril de 2012

Linguagem Scala: a primeira impressão


A linguagem que vem sendo considerada a "substituta" do Java, chama a atenção em muitos sentidos, inclusive por ser a linguagem utilizada no core de duas das mais famosas aplicações da atualidade, o FourSquare e o Twitter. O nome dessa linguagem? Scala.

Bem... sob uma análise mais emocional eu posso dizer que a linguagem é "massa", "sensacional"... Mas por uma análise mais, fria, racional, posso afirmar que o seu aprendizado é mais demorado que a do Java. Por que? Bem... para entender apenas da linguagem Java, você basta compreender alguns conceitos basicos, tais como: Classes, Interfaces, Métodos, Variáveis, Enumerações, Loops (for, foreach e while), If...Else, Switch, etc. Pois bem... para aprender Scala você precisa ter estes conhecimentos e muito mais, tais como: Case Class, Trait, Object, For-Comprehensive, Product, Actor, Function, etc... 

Outra diferença, e daí mais necessidade de conhecimento, relacionado ao Java, é que a linguagem Scala segue o paradigma Funcional e Orientado à Objeto. Isto quer dizer que além de entender POO (Programação Orientada à Objeto), você precisa compreender ainda de Funcional Paradigm. 

Apesar de seguir o paradigma funcional, segundo Sebesta, uma linguagem não deveria ter atribuíções e nem variáveis, diferente do que pode-se observar na languagem Scala. Por um outro lado esta linguagem deve prover uma diversidade de funções básicas que poderão ajudar o desenvolvedor a criar funções complexas. Neste ponto, Scala segue a linha! 

Talvez você se pergunte: então qual é realmente a grande vantagem da languagem Scala? Esta resposta eu darei quando eu finalizar uma aplicação que estou desenvolvendo, para não repetir apenas as vantagens que tem nos livros, blogs, etc - algumas destas você pode ver aqui. O que posso adiantar por enquanto é que a quantidade de conceitos novos é muito grande, no entanto quando você consegue entender isto a programação se torna mais rápida e mais intuítiva, dado que você pode agrupar e controlar o acesso aos dados em um único arquivo, a programação de Collections requer escrita de código, a comunicação com Bancos de Dados (apesar de se utilizar JDBC) é muito mais rápida que utilizar ORM ou SQL diretamente (pelo menos na minha opnião). Quer um exemplo disso? 

  //cria a representação de uma tabela de usuários
  val Users = new Table[(String, String)]("TBUSER"){
      def nick = column[String]("nick")
      def password = column[String]("password")
      def * = nick ~ password
    }
    //realizar a consulta
    val list: List[(String,String)] = Database.forURL(
    uri = "jdbc:postgresql://localhost:5432/db_scala",
    user = "postgres", 
    password = "123456",
    driver = "org.postgresql.Driver"
    ).withSession(
        Query(user).where(f => f.name === "1").list()
    )
    //imprimir todos os dados da tabela
    list.foreach(println)

Simples não?? O melhor de tudo é como nós podemos organizar nossos códigos! Bem... o resto explico num outro momento.

Bons estudos e até lá!







sábado, 7 de abril de 2012

GWT Applications

GWT ou Google Web Toolkits é uma tecnologia interessante para construção de aplicações RIA para web. E como toda tecnologia possui vantagens e desvantagens. Uma das grandes desvantagens que vejo é a dificuldade de utilização dos widgets nos pacotes de Cells (CellList, CellTable, ...). Caso eu queria adicionar um widget do tipo PushButton, não é possível, pois a construção das cells em tempo de compilação são feitas com SafeHtml, e este por sua vez não permite nenhuma chamada dinâmica, ou seja, não posso criar uma classe de extensão de AbstractCell<C> e implementar o método render com o conteúdo abaixo, pois as imagens não serão renderizadas:

//ImageBundle is ClientBundle instacied in "instance" variable.
Image upImage = new Image(ImageBundle.instance.commandBlock30x30());
Image downImage = new Image(ImageBundle.instance.commandBlockDown30x30());
//create push button
PushButton pb = new PushButton(upImage, downImage);
//
SafeHtmlBuilder sfb = new SafeHtmlBuilder();
sfb.appendHTMLConstant(.pb.toString());

O resultado deste comando é a implementação parcial das tags necessárias para a construção do PushButton. Em outras palavras, você não verá imagem nenhum ali! A curiosidade bateu e fui pesquisa porque isto acontece e o fato mais interessante vem no próprio SafeHtml (via java doc):


The method that appends constant strings (appendHtmlConstant(String)) requires a convention of use to be adhered to in order for this class to adhere to the contract required by SafeHtml: The argument expression must be fully determined and known to be safe at compile time, and the value of the argument must not contain incomplete HTML tags

Ou seja: qualquer elemento que eu colocar ali que precisa de alguma renderização, como é o caso do PushButton, que necessita da renderização posterior das imagens, não irá funcionar. Então como construir? Construa o pushbutton assim:

//...
PushButton pb = new PushButton();
pb.getUpFace().setHTML("<img src='" + ImageBundle.instance.commandBlock30x30().getURL() + "' >");
pb.getDownFace().setHTML("<img src='" + ImageBundle.instance.commandBlockDown30x30().getURL() + "' >");
//...

Parece uma "gambirra" (como chamamos aqui a famosa gambiarra), mas se ler a documentação é uma proteção contra ataque, o que me deixa muito tranquilo para transmitir esta solução.


Até a próxima.

quarta-feira, 4 de abril de 2012

Gamification

Quando a empresa Webdroid foi pensada, uma das maiores preocupações era: "como construir aplicações para a web e mobile (no caso, android) para negócios". Há cerca de um ano atrás isto não estava bem formatado, mas veio então a ideia da construção do WLance. Um sistema de ecommerce diferente, cujas vendas são baseadas em jogos. O tempo passou, e hoje, as ideias estão mais maduras e o que tenho certeza é que Webdroid é uma empresa voltada para desenvolvimento de inovação de negócios utilizando-se de aplicações "multi-plataforma".

Uma das inovações propostas pela Webdroid é a construção e personalização de aplicações para gerar publicidade e venda utilizando-se do conceito de Gamification. O conceito em si não é novo, mas a sua ampla utilização em diversos ramos de negócios e em diferentes contextos, sim.

Atualmente, no meu mestrado, estou estudando "como uma empresa de e-commerce pode incentivar uma venda utilizando-se de mecânica de jogo?". 
No Brasil existem poucos estudos de casos, pelo menos divulgado, sobre a utilização efetiva de uma mecânica de jogo aplicada para o incentivo de uma venda. E quando o assunto é ecommerce, este é ainda mais difícil de ver algum caso. Para falar a verdade, no Brasil ainda não vi nenhum.

Então a Webdroid comprou um desafio. Criar uma aplicação de incentivo a venda ou publicidade de um produto ou marca.  Como será isto? Bem... veremos nos próximos 2 ou 3 meses.

Então aguardem!


Pesquise aqui!