terça-feira, 21 de julho de 2015

Mapeamento de polimorfismo com @Any no Brutos MVC

O mapeamento de polimorfismo, introduzido na versão 2.0, é uma solução que permite a um entidade ser mapeada para mais de um tipo. É implementado com a anotação @Any. Este tipo de mapeamento requer que, além do mapeamento da entidade, seja informado o metabean, uma variável que contém o identificador da entidade associada. Pode ser usado em um bean nas propriedades ou nos argumentos de um construtor e em um controlador nas propriedades ou nos parâmetros de uma ação.


@Target({ElementType.METHOD,ElementType.PARAMETER,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Any {

 Basic metaBean() default @Basic;
 Class metaType() default String.class;
 EnumerationType metaEnumerated() default EnumerationType.ORDINAL;
 String metaTemporal() default BrutosConstants.DEFAULT_TEMPORALPROPERTY;
 MetaValue[] metaValues() default {};
 Class metaValuesDefinition() default MetaValuesDefinition.class;
 
}


  • metaBean(): variável que contém os metadados.
  • metaType(): tipo da variável que contém os metadados.
  • metaEnumerated(): usado quando o metadado for uma enumeração.
  • metaTemporal(): usado quando o metadado for uma data.
  • metaValues(): associa um valor a um bean.
  • metaValuesDefinition(): Permite em tempo de execução associar um valor a um bean.

Abaixo um exemplo de uso da anotação @Any em uma propriedade de um bean.

public class TestBean{

    @Basic(bean="property")
    @Any(
        metaBean=@Basic(bean="property_type")
        metaValues={
            @MetaValue(name="Decimal", target=DecimalProperty.class),
            @MetaValue(name="Set", target=SetProperty.class)
        }
    )
    private Property property

    ...
}

Abaixo um exemplo de uso da anotação @Any em um construtor de um bean.

public class TestBean{

    public TestBean(
        @Basic(bean="property")
        @Any(
            metaBean=@Basic(bean="property_type")
            metaValues={
                @MetaValue(name="Decimal", target=DecimalProperty.class),
                @MetaValue(name="Set", target=SetProperty.class)
            }
        )
        Property property){
        ...
    }

}

Abaixo um exemplo de uso da anotação @Any em uma propriedade de um controlador.

@Controller("/test")
public class TestController{

    @Basic(bean="property")
    @Any(
        metaBean=@Basic(bean="property_type")
        metaValues={
            @MetaValue(name="Decimal", target=DecimalProperty.class),
            @MetaValue(name="Set", target=SetProperty.class)
        }
    )
    private Property property

    ...
}

Abaixo um exemplo de uso da anotação @Any em uma ação.

@Controller("/test")
public class TestController{

    @Action("/")
    public void testAction(
        @Basic(bean="property")
        @Any(
            metaBean=@Basic(bean="property_type")
            metaValues={
                @MetaValue(name="Decimal", target=DecimalProperty.class),
                @MetaValue(name="Set", target=SetProperty.class)
            }
        )
        Property property){
        ...
    }

}

Um exemplo da vida real seria um cenário de venda, onde um operador turístico vende diferentes serviços.
O exemplo irá permitir registrar um serviço aéreo ou de hospedagem por transação.

Dowload linkhttp://sourceforge.net/projects/brutos/files/brutos/2.0/examples/2.0-RC1/polymorphic-mapping.zip/download

Source codehttp://sourceforge.net/p/brutos/code/HEAD/tree/trunk/examples/polymorphic-mapping/


Diagrama das entidades da aplicação.


Durante cada transação de venda, apenas um serviço será vendido. Podendo ser um serviço de hospedagem ou aéreo.

Classes

public class SaleTransaction {

 private Long id;

 @Transient
 private Date date;

 private Long price;

 @Any(
  metaBean = 
   @Basic(bean = "serviceType"),
  metaType=
   String.class,
  metaValues = {
   @MetaValue(name = "air", target = AirService.class),
   @MetaValue(name = "hosting", target = HostingService.class) 
  }
 )
 private Service service;

 //gets e sets
 ...

}
SaleTransaction.java

A anotação @Any indica que a propriedade service receberá uma instâncias da AirService, se o parâmetro serviceType for igual a "air", ou HostingServices, se o parâmetro serviceType for igual a "hosting".

public interface Service {

 void setPrice(Long value);
 
 Long getPrice();
 
 String getServiceType();
 
}
Service.java

public abstract class AbstractService 
 implements Service{

 protected Long price;
 
 public void setPrice(Long value) {
  this.price = value;
 }

 public Long getPrice() {
  return this.price;
 }

}
AbstractService.java

public class AirService extends AbstractService{

 private String airplane;
 
 private String seat;
 
 @Temporal("yyyy-MM-dd hh:mm")
 private Date departureDate;
 
 @Temporal("yyyy-MM-dd hh:mm")
 private Date arrivalDate;

 public String getAirplane() {
  return airplane;
 }

 //gets e sets
 ...
 
}
AirService.java

public class HostingService extends AbstractService{

 private String hotel;
 
 @Temporal("yyyy-MM-dd")
 private Date checkin;
 
 @Temporal("yyyy-MM-dd")
 private Date checkout;
 
 private String mealPlan;
 
 private String room;

 //gets e sets
 ...
 
}
HostingService.java

@Controller("/sales")
@Action(value="/new", view=@View("new"))
@RequestScoped
public class SalesController {

 @Inject
 @Transient
 private SalesMemoryEntityAccess salesMemoryEntityAccess;
 
 @Action("/save")
 @Result("entity")
 public SaleTransaction save(@Basic(bean="entity") 
  SaleTransaction entity){
  this.salesMemoryEntityAccess.save(entity);
  return entity;
 }

 ...
 
}
SalesController.java


View


<form method="POST"
  action="${pageContext.servletContext.contextPath}/sales/save">
  <table>
   <tbody>
<tr>
     <td>Id</td>
     <td>${entity.id}</td>
    </tr>
<tr>
     <td>Price</td>
     <td><input type="text" name="entity.price"
      value="${entity.price}"></td>
    </tr>
<tr>
     <td>Service type</td>
<!-- campo do metaBean serviceType -->
     <td><select id="serviceType" name="entity.service.serviceType"
      onchange="javascript:showServiceDataundefined)">
       <option ${entity.service.serviceType == 'air'? "selected " : ""} value="air">Air</option>
       <option ${entity.service.serviceType == 'hosting'? "selected " : ""} value="hosting">Hosting</option>
     </select></td>
    </tr>
<!-- inicio do formulário do serviço aéreo -->
<tr id="air">
     <td>
      <table width="100%">
       <tbody>
<tr>
         <td>Airplane</td>
         <td><input type="text" name="entity.service.airplane"
          value="${entity.service.serviceType != 'air'? null : entity.service.airplane}"></td>
        </tr>
<tr>
         <td>Departure date</td>
         <td><input type="text" name="entity.service.departureDate"
          value="<fmt:formatDate value="${entity.service.serviceType != 'air'? null : entity.service.departureDate}" pattern="yyyy-MM-dd hh:mm" />"></td>
        </tr>
<tr>
         <td>Arrival date</td>
         <td><input type="text" name="entity.service.arrivalDate"
          value="<fmt:formatDate value="${entity.service.serviceType != 'air'? null : entity.service.arrivalDate}" pattern="yyyy-MM-dd hh:mm" />"></td>
        </tr>
</tbody>
      </table>
</td>
    </tr>
<!-- inicio do formulário do serviço de hospedagem -->
<tr id="hosting">
     <td>
      <table width="100%">
       <tbody>
<tr>
         <td>Hotel</td>
         <td><input type="text" name="entity.service.hotel"
          value="${entity.service.serviceType != 'hosting'? null : entity.service.hotel}"></td>
        </tr>
<tr>
         <td>Checkin</td>
         <td><input type="text" name="entity.service.checkin"
          value="<fmt:formatDate value="${entity.service.serviceType != 'hosting'? null : entity.service.checkin}" pattern="yyyy-MM-dd" />"></td>
        </tr>
<tr>
         <td>Checkout</td>
         <td><input type="text" name="entity.service.checkout"
          value="<fmt:formatDate value="${entity.service.serviceType != 'hosting'? null : entity.service.checkout}" pattern="yyyy-MM-dd" />"></td>
        </tr>
<tr>
         <td>Mealplan</td>
         <td><input type="text" name="entity.service.mealPlan"
          value="${entity.service.serviceType != 'hosting'? null : entity.service.mealPlan}"></td>
        </tr>
<tr>
         <td>Room</td>
         <td><input type="text" name="entity.service.room"
          value="${entity.service.serviceType != 'hosting'? null : entity.service.room}"></td>
        </tr>
</tbody>
      </table>
</td>
    </tr>
</tbody>
   <tfoot>
<tr>
     <td><c:if test="${!empty entity.id}">
       <input type="hidden" name="entity.id" value="${entity.id}">
      </c:if> <input type="submit" value="Submit"></td>
    </tr>
</tfoot>

  </table>
</form>


http://www.brutosframework.com.br/

domingo, 5 de julho de 2015

Brutos Framework 2.0 RC1 Released

The Brutos Application Framework is MVC controller developed in Java. Designed to reduce the complexity of web development, with configurable mapping, view resolution as well as support for uploading and downloading files. Can be configured using XML, annotations and CoC.

Highlights of the 2.0 RC1 release: 

  • added support to polymorphic mapping. 
  • Bean Validation is the default validator provider. 
  • CDI is the default object provider. 

http://www.brutosframework.com.br/