Spring MVC
I've worked with Spring MVC 3.0 and Spring MVC 4.0 from Java
This site, is builded with Spring, using some basic functions.
MVC.xml Configuration
<mvc:resources location="/img/" mapping="/img/**" />
<mvc:resources location="/css/" mapping="/css/**" />
<mvc:resources location="/js/" mapping="/js/**" />
<bean id="viewResolver" class="org.springframework.web.servlet.view.tiles3.TilesViewResolver"/>
<bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/tiles.xml</value>
</list>
</property>
</bean>
<bean id="globalController" class="com.genexis.ccorona.HelloAppEngine" />
To optimize the application loading for App Engine, I don't activate the automatic scanning of controllers, so I manually register my unique controller, plus, I specify which files will be used as static resources and include Tiles as view resolver.
Principal Controller
@Controller
@RequestMapping(value="/")
public class HelloAppEngine {
private static final Logger logger = Logger.getLogger(HelloAppEngine.class.getName());
@RequestMapping(value="**", method=RequestMethod.GET, produces="text/html")
public ModelAndView viewPage(HttpServletRequest req) throws IOException {
String request = req.getRequestURI();
request = request.length() > 0 ? request.substring(1) : request;
logger.info(request);
if (request.trim().isEmpty()) {
request = "index";
}
ModelAndView mav = new ModelAndView(request.replaceAll("\\/", "."));
return mav;
}
}
In this way, with an unique controller, in a few code lines, I decide which view of defined on Tiles will be presented, depending of the request path. This allows me increase quickly the site.
Tiles
I've worked with Tiles 2.0 and Tiles 3.0 integrating them on projects with Spring MVC
In fact, this site it's builded using tiles, with a configuration that allows create new pages in a agile way, where each section includes a layout with parallax functions, and materialize.
Base Tiles Structure
<definition name='base' template='/WEB-INF/templates/pages/layout.jsp' >
<put-attribute name='title' value='Carlos Corona' cascade='true'/>
<put-attribute name='sidemenu' value='/WEB-INF/templates/components/sidemenu.jsp' cascade='true'/>
</definition>
Index Screen Structure:
<definition name="index" extends="base">
<put-attribute name="banner" value="/WEB-INF/templates/components/banner.jsp" cascade="true" />
<put-list-attribute name="sections" cascade="true" >
<add-attribute value="/WEB-INF/templates/components/index.jsp" />
</put-list-attribute>
<put-list-attribute name="images" cascade="true">
<add-attribute value="ccorona.png" />
</put-list-attribute>
</definition>
Work Section Definition (example)
<definition name="work" extends="base">
<put-list-attribute name="sections" cascade="true" >
<add-attribute value="/WEB-INF/templates/components/overcome.jsp" />
<add-attribute value="/WEB-INF/templates/components/orcius.jsp" />
<add-attribute value="/WEB-INF/templates/components/inaoe.jsp" />
</put-list-attribute>
<put-list-attribute name="titles" cascade="true">
<add-attribute value="BIOvercome SAPI de C.V. (Overcome)" />
<add-attribute value="Express Web Consortium (Orcius)" />
<add-attribute value="Instituto Nacional de Astrofísic Óptica y Electrónica (INAOE)" />
</put-list-attribute>
</definition>
System Layout
The file layout.jsp defines the general structure of the template.
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="t" uri="http://tiles.apache.org/tags-tiles" %>
<%@ taglib prefix="te" uri="http://tiles.apache.org/tags-tiles-extras" %>
<te:useAttribute id="scripts" name="scripts" classname="java.util.List" ignore="true" />
<te:useAttribute id="styles" name="styles" classname="java.util.List" ignore="true" />
<te:useAttribute id="sections" name="sections" classname="java.util.List" ignore="true" />
<te:useAttribute id="titles" name="titles" classname="java.util.List" ignore="true" />
<te:useAttribute id="subtitles" name="subtitles" classname="java.util.List" ignore="true" />
<te:useAttribute id="images" name="images" classname="java.util.List" ignore="true" />
<!DOCTYPE html>
<html>
<head>
<title><t:getAsString name="title" ignore="true" /></title>
<link href="/css/basic.css" rel="stylesheet" type="text/css"/>
<!-- Estilos para Materialize -->
<link href='//fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css' />
<link href='//fonts.googleapis.com/css?family=Roboto+Condensed' rel='stylesheet' type='text/css' />
<link href="//fonts.googleapis.com/css?family=Montserrat:400,700" rel="stylesheet" type="text/css" />
<link href="//fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.7/css/materialize.min.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
</head>
<body>
<!-- Componente fijo de menú lateral -->
<t:insertDefinition name="component.sidemenu"/>
<!-- Componente fijo de barra superior de navegación -->
<t:insertDefinition name="component.navbar" />
<!-- Opcionalmente, puedo incluir un 'banner' en cada sección -->
<t:insertAttribute name="banner" ignore="true" />
<!-- Incluyo los distintos bloques (secciones) de la página que se muestra, aplicando un separador con efecto Parallax -->
<c:forEach items="" var="section" varStatus="i">
<div class="parallax-container valign-wrapper">
<div class="section no-pad-bot">
<div class="container">
<div class="row center">
<c:if test="false">
<h3 class="header center white-text text-lighten-2"><c:out value="" /></h3>
</c:if>
<c:if test="false">
<h4 class="header col s12 light"><c:out value="" /></h4>
</c:if>
<c:if test="false">
<img src="/img/" class="circle responsive-img" />
</c:if>
</div>
</div>
</div>
<div class="parallax">
<img src="/img/background_.jpg" />
</div>
</div>
<div class="container">
<div class="section">
<t:insertAttribute value="" flush="true" ignore="true" />
</div>
</div>
</c:forEach>
<!-- Configuración final de Materialize para inicializar la página -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.7/js/materialize.min.js"></script>
<script>
(function($){
$(function(){
$('.button-collapse').sideNav();
$('.parallax').parallax();
}); // end of document ready
})(jQuery); // end of jQuery name space
</script>
</body>
</html>
In this way, I can include new sections to site creating new definitions on the tiles file, each one can refferer or include distinct functions (like index does), but maintain the same structure of template.
AppEngine
I started working on Google App Engine while I was working on Orcius, where after research about different cloud features and services as Microsoft Azure, Amazon and Google, I decided for the last one because the complete ecosystem.
Since then, I've been updating myself in the use of services that it has to offer, like building Virtual Machines, integrating API's like maps and geo-location, endpoints for mobile applications, etc. At same time, I've highlighted on design and building of Object Oriented Data Bases.
For work with Google Cloud Datastore, I've builded my own framework based on Objectify 5.0,, in this way, I can build and consume its services in a fastest way.
¿Objectify?
One Google's library for work with No Relational Data Bases, it's currently version 5. However, today, the effort to integrate inside a proyect generates lots of 'noise' code. For this reason, I've builded my own framework
Generalizing Objectify
First at all, Objectify doesn't works with types during the compilation process, so it's easy get confused, for solve this, I've generalizated the class and overwrited the mos common methods, so I can have it all easily called whit correct type. The most important methods of the class are the most elemental ones: add, delete, get, list, listByProperty and all they are lot overloaded with different args
public class ObjectifyDao<T> {
protected Class<T> clazz;
public ObjectifyDao(Class<T> clazz) {
this.clazz = clazz;
}
public Key<T> add(T entity) {
Result<Key<T>> result = ObjectifyService.ofy().save().entity(entity);
return result.now();
}
public Map<Key<T>, T> add(List<T> counts) {
Result<Map<Key<T>, T>> result = ObjectifyService.ofy().save().entities(counts);
return result.now();
}
public void delete(T entity) {
ObjectifyService.ofy().delete().entity(entity);
}
public void delete(Collection<Key<T>> entities) {
ObjectifyService.ofy().delete().entities(entities);
}
public void delete(Key<T> entityKey) {
ObjectifyService.ofy().delete().key(entityKey);
}
public T get(Key<T> key) throws EntityNotFoundException {
Result<T> result = ObjectifyService.ofy().load().key(key);
return result.now();
}
public Map<Key<T>, T> get(Collection<Key<T>> keys) {
return ObjectifyService.ofy().load().keys(keys);
}
public List<T> getAllList(Key<?> parentKey) {
Query<T> q = ObjectifyService.ofy().load().type(clazz).ancestor(parentKey);
return q.list();
}
public List<T> getAllList(String order, int offset, int limit) {
Query<T> q = ObjectifyService.ofy().load().type(clazz);
if (order != null && !order.trim().isEmpty()){
q = q.order(order);
}
q = q.offset(offset).limit(limit);
return q.list();
}
...
I've created one interface who any object manager can implements for work with datastore's entities
public interface EntityService<T>{
public void setObjectifyDao(ObjectifyDao<T> ofyDao);
public T load(Key<T> key);
public T load(String key);
public Map<Key<T>, T> load(Collection<Key<T>> keys);
public Key<T> save(T entity);
public Map<Key<T>, T> save(List<T> entity);
public void delete(Key<T> key);
public void deleteEntities(List<Keyable<T>> keys);
public void delete(List<Key<T>> keys);
public List<T> list(Key<?> parent);
public List<T> list(Key<?> parent, String order, int offset, int limit);
public List<T> list(Key<?> parent, int offset, int limit);
public List<T> list();
public List<T> list(int offset, int limit);
public List<T> list(String order, int offset, int limit);
public boolean isHardRequired();
public void setHardRequired(boolean hardRequired);
}
Lot of entities must implement this interface with equivalent procedures, so I created one class that can be heredated and it realizes some of the common process:
public abstract class EntityServiceImpl<T> implements EntityService<T> {
protected ObjectifyDao<T> dao;
protected boolean hardRequired = false;
public boolean isHardRequired() { return hardRequired; };
public void setHardRequired(boolean hardRequired) {
this.hardRequired = hardRequired;
}
public void setObjectifyDao(ObjectifyDao<T> objectifyDao) {
this.dao = objectifyDao;
}
@Override
public T load(Key<T> key) {
try {
return isHardRequired() ? dao.getHard(key) : dao.get(key);
} catch (Exception e) {
return null;
}
}
@Override
public T load(String keyString) {
if (keyString != null && !keyString.trim().isEmpty()){
Key<T> key = Key.create(keyString);
return load(key);
}
return null;
}
@Override
public Map<Key<T>, T> load(Collection<Key<T>> keys) {
return dao.get(keys);
}
@Override
public Key<T> save(T entity) {
return isHardRequired() ? dao.addHard(entity) : dao.add(entity);
}
@Override
public Map<Key<T>, T> save(List<T> entity) {
return dao.add(entity);
}
@Override
public void delete(Key<T> key) {
dao.delete(key);
}
public void deleteEntities(List<Keyable<T>> objects) {
List<Key<T>> keys = new ArrayList<>(objects.size());
for (Keyable<T> o : objects) {
keys.add(o.getKey());
}
dao.delete(keys);
}
public void delete(List<Key<T>> keys) {
dao.delete(keys);
}
@Override
public List<T> list(Key<?> parentKey) {
if (parentKey != null) {
return dao.getByParentId(parentKey);
} else {
return dao.getAllList();
}
}
@Override
public List<T> list(Key<?> parentKey, int offset, int limit) {
return list(parentKey, null, offset, limit);
}
@Override
public List<T> list(Key<?> parentKey, String order, int offset, int limit) {
if (parentKey != null) {
return dao.getList(parentKey, order, offset, limit);
} else {
return dao.getAllList(order, offset, limit);
}
}
@Override
public List<T> list() {
return dao.getAllList();
}
@Override
public List<T> list(int offset, int limit) {
return list("", offset, limit);
}
@Override
public List<T> list(String order, int offset, int limit) {
return dao.getAllList(order, offset, limit);
}
}
This classes and interfaces are defined inside my own library, so any project that wants implement them, just needs to create an Entity class the services with a few code lines
EntityClass, EntityService y EntityServiceImpl
Starting from a EntityExample class, build a process to access the Datastore its really simple
@Entity
public class EntidadEjemplo {
@Id private Long id;
private String dato;
@Index private Date fecha;
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getDato() { return dato; }
public void setDato(String dato) { this.dato = dato; }
public Date getFecha() { return fecha; }
public void setFecha(Date fecha) { this.fecha = fecha; }
}
I build an interface that allows me customize the behavior on the future, in this case, I just sólo extends from EntityService
public interface EntidadEjemploService extends EntityService<EntidadEjemplo> {}
Then I build a class which implements the interface recently created, inherit from EntityServiceImpl
public class EntidadEjemploServiceImpl implements EntidadEjemploService extends EntityServiceImpl<EntidadEjemplo> {}
With this, without any other code line, I can access the basic methods of Objectify which I had overloaded, with hard type defined, on any block I require
public class FuncionesEjemplo {
private EntidadEjemploService ees = ServiceFactory.getInstance().getEntidadEjemploService();
public String registrarEjemplo(Date hoy, String dato) {
EntidadEjemplo ee = ees.getByProperty("fecha", hoy);
if (ee == null) {
ee = new EntidadEjemplo();
}
ee.setDato(dato);
Key<EntidadEjemplo> key = ees.save(dato);
return key.getString();
}
}
Spring Configuration
As part of additional configurations required by Objectify, any entity must be initiated before we can use it to read/write, so I created a class OfyService who works in a singleton way, builded when the app starts with an Objectify instance and the register of working classes
Finally, like in the example, usually I mantain a singleton ServiceFactory that allows me access the services wherever I am on the project code
...
<bean id="OfyService" class="com.genexis.dao.OfyService" factory-method="getInstance">
<constructor-arg name="classes">
<array value-type="java.lang.Class">
<value>com.genexis.ccorona.entity.EntidadEjemplo</value>
...
</array>
</constructor-arg>
</bean>
...
<bean id="entidadEjemploDao" class="com.genexis.dao.ObjectifyDao">
<constructor-arg name="clazz" value="com.genexis.ccorona.entity.EntidadEjemplo" />
</bean>
<bean id="entidadEjemploService" class="com.genexis.ccorona.service.impl.EntidadEjemploServiceImpl">
<property name="objectifyDao" ref="entidadEjemploDao" />
</bean>
<bean id="ServiceFactory" class="com.genexis.ServiceFactory" factory-method="getInstance">
<property name="entidadEjemploService" ref="entidadEjemploService" />
...
</bean>
Maven
From this project, I'm starting to work with Maven 3.0, building the project starting from the Archetipe of Google Cloud, Although, I'm planning define my own archetipe, including my libraries and functions as part of every new project, so any new integration will require only the building of business logic modules.