Skip to content

Instantly share code, notes, and snippets.

@cmilfont
Created December 27, 2011 20:21
Show Gist options
  • Save cmilfont/1525013 to your computer and use it in GitHub Desktop.
Save cmilfont/1525013 to your computer and use it in GitHub Desktop.
Gerar a representação dos controllers do VRaptor em javascript
/* Começado em https://gist.github.com/1524693 */
package org.milfont.indica.controller;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import net.vidageek.mirror.dsl.Mirror;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Transformer;
import org.apache.commons.lang.StringUtils;
import br.com.caelum.vraptor.Get;
import br.com.caelum.vraptor.Path;
import br.com.caelum.vraptor.Resource;
import br.com.caelum.vraptor.Result;
import br.com.caelum.vraptor.http.route.Route;
import br.com.caelum.vraptor.http.route.Router;
import br.com.caelum.vraptor.resource.ResourceMethod;
import br.com.caelum.vraptor.view.Results;
import com.google.common.collect.Multimap;
import com.google.common.collect.Ordering;
import com.google.common.collect.TreeMultimap;
@Resource
public final class DirectJavascriptRemote {
private final Router router;
private final Result result;
public DirectJavascriptRemote(Router router, Result result) {
this.router = router;
this.result = result;
}
final String controllerTemplate = "function #{controller_name}(){DJR.call(this);}; #{controller_name}.prototype.routes = {};";
final String actionsTemplate = "\n #{controller_name}.prototype.routes['#{action}'] = {url: \"#{uri}\", method: \"#{method}\" };";
@SuppressWarnings({ "unchecked"})
private Set<String> filterControllerNames(List<Route> routes) {
Collection<String> names = CollectionUtils.collect(routes, new Transformer(){
@Override
public Object transform(Object obj) {
Route route = (Route) obj;
ResourceMethod resourceMethod = (ResourceMethod) new Mirror().on(route).get().field("resourceMethod");
return resourceMethod.getMethod().getDeclaringClass().getSimpleName();
}});
Comparator<String> comparator = new Comparator<String>() {
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
};
Multimap<String, String> groups = TreeMultimap.create(comparator, Ordering.arbitrary());
for(String controllerName : names) {
groups.put(controllerName, controllerName);
}
return groups.asMap().keySet();
}
@Get
@Path("/djr")
public void getControllers() {
StringBuilder builder = new StringBuilder();
String routesText = "";
List<Route> routes = router.allRoutes();
Set<String> controllerNames = filterControllerNames(routes);
for(String name : controllerNames) {
routesText = StringUtils.replace(controllerTemplate, "#{controller_name}", name);
builder.append(routesText).append("\n");
}
for (Route route : routes) {
String verb = route.allowedMethods().toArray()[0].toString();
String uri = route.getOriginalUri();
ResourceMethod resourceMethod = (ResourceMethod) new Mirror().on(route).get().field("resourceMethod");
String controllerName = resourceMethod.getMethod().getDeclaringClass().getSimpleName();
String action = resourceMethod.getMethod().getName();
routesText = StringUtils.replace(actionsTemplate, "#{controller_name}", controllerName);
routesText = StringUtils.replace(routesText, "#{action}", action);
routesText = StringUtils.replace(routesText, "#{uri}", uri);
routesText = StringUtils.replace(routesText, "#{method}", verb);
builder.append(routesText).append("\n");
}
result.use(Results.http()).body(builder.toString());
}
}
/* foi feito para o Rails primeiro, tem que fazer alguns ajustes */
function toMap(object) {
var arr = [];
for(var item in object)
arr[arr.length] = {key: item, value: object[item]};
return arr;
};
var DJR = function() {
this.data = "";
this.error = {};
this.format = ".json";
this.formatURL = function(url, params) {
toMap(params).each( function(param) {
url = url.replace((new RegExp(param.key)).source, param.value);
});
return url;
};
this.callbackDefault = function(data) {
this.data = data;
};
this.errorDefault = function(error) {
this.error = error;
};
this.ajax = function(object, callback, error, method, url, params) {
var self = this;
var params = params || [];
params["\(.:format\)"] = this.format;
if(method === "")
method = "GET";
toMap(object).each( function(param) {
params[":" + param.key] = param.value;
});
if(method !== "GET") {
object = JSON.stringify(object);
if (object && object.length === 2)
object = null;
}
if(method === "DELETE") object = null;
jQuery.ajax({
context : self,
data : object,
cache : false,
dataType : 'json',
error : error,
success : callback,
contentType : "application/json",
headers : {"Content-Type":"application/json", "Accept":"application/json"},
type : method,
url : this.formatURL(url, params) + "?authenticity_token=" + $("meta[name='csrf-token']").attr("content")
});
};
for (var action in this.routes) {
this[action] = function(act) {
return function(object, callback, error) {
if(typeof object === "function") {
callback = object;
error = callback;
object = {};
}
var localCallback = callback || this.callbackDefault;
var localErrorHandler = error || this.errorDefault;
this.ajax(object,
localCallback,
localErrorHandler,
this.routes[act].method,
this.routes[act].url);
return this;
}
}(action);
}
};
function ClientesController(){DJR.call(this);}; ClientesController.prototype.routes = {};
function ContatosController(){DJR.call(this);}; ContatosController.prototype.routes = {};
function DirectJavascriptRemote(){DJR.call(this);}; DirectJavascriptRemote.prototype.routes = {};
function HomeController(){DJR.call(this);}; HomeController.prototype.routes = {};
function OportunidadesController(){DJR.call(this);}; OportunidadesController.prototype.routes = {};
function ProdutosController(){DJR.call(this);}; ProdutosController.prototype.routes = {};
DirectJavascriptRemote.prototype.routes['getControllers'] = {url: "/djr", method: "GET" };
OportunidadesController.prototype.routes['create'] = {url: "/oportunidades", method: "POST" };
OportunidadesController.prototype.routes['index'] = {url: "/oportunidades", method: "GET" };
OportunidadesController.prototype.routes['show'] = {url: "/oportunidades/{oportunidade.id}", method: "GET" };
OportunidadesController.prototype.routes['nova'] = {url: "/oportunidades/nova", method: "GET" };
HomeController.prototype.routes['index'] = {url: "/", method: "GET" };
ProdutosController.prototype.routes['index'] = {url: "/produtos", method: "GET" };
ClientesController.prototype.routes['index'] = {url: "/clientes", method: "GET" };
ContatosController.prototype.routes['index'] = {url: "/contatos", method: "GET" };
OportunidadesController.prototype.routes['indicar'] = {url: "/oportunidades/indicar", method: "POST" };
var controller = new OportunidadesController;
// usando https://github.com/milfont/jsonform/ para capturar objeto a partir do FORM
var oportunidade = $("form").getJSON();
controller.create( oportunidade, callback, errorHandler);
@wpivotto
Copy link

Muito bom esse gist, muito útil...

Uma melhoria seria criar o seguinte componente que recupera o nome de todos os controllers:

@Component
@ApplicationScoped
public class Controllers implements StereotypeHandler {

    private Set<String> controllers = Sets.newHashSet();

    public Class<? extends Annotation> stereotype() {
        return Resource.class; // intercepta todos os controllers
    }

    public void handle(Class<?> controller) {
        controllers.add(controller.getSimpleName());
    }

    public Set<String> all() {
        return Collections.unmodifiableSet(controllers);
    }
}

@cmilfont
Copy link
Author

wpivotto gostei da idéia, ainda vamos pegar esse esboço e dar uma trabalhada nele. Mais sugestões são muito bem vindas.

@plentz
Copy link

plentz commented Mar 31, 2014

@cmilfont como vocês tão tratando CSRF? interceptor mesmo?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment