package br.com.caelum.restfulie.relation;
import java.util.Random;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtField;
import javassist.CtNewMethod;
import javassist.LoaderClassPath;
import javassist.NotFoundException;
import br.com.caelum.restfulie.Resource;
@SuppressWarnings("rawtypes")
public class DefaultEnhancer implements Enhancer {
public <T> Class enhanceResource(Class<T> originalType) {
ClassPool pool = ClassPool.getDefault();
if (pool.find(DefaultEnhancer.class.getName()) == null) {
pool.appendClassPath(new LoaderClassPath(getClass().getClassLoader()));
}
try {
// TODO extract this enhancement to an interface and test it appart
CtClass newType = pool.makeClass(generateNewUniqueClassName(originalType));
newType.setSuperclass(pool.get(originalType.getName()));
newType.addInterface(pool.get(Resource.class.getName()));
enhanceLinks(newType);
return newType.toClass();
} catch (NotFoundException e) {
throw new IllegalStateException("Unable to extend type " + originalType.getName(), e);
} catch (CannotCompileException e) {
throw new IllegalStateException("Unable to extend type " + originalType.getName(), e);
}
}
private <T> String generateNewUniqueClassName(Class<T> originalType) {
return "br.com.caelum.restfulie." + originalType.getSimpleName() + "_" + System.currentTimeMillis() + new Random().nextLong();
}
private void enhanceLinks(CtClass newType) throws CannotCompileException {
CtField field = CtField.make("public java.util.List link = new java.util.ArrayList();", newType);
newType.addField(field);
newType.addMethod(CtNewMethod.make("public java.util.List getLinks() { return link; }", newType));
newType.addMethod(CtNewMethod.make("public java.util.List getLinks(String rel) { java.util.List links = new java.util.ArrayList(); for(int i=0;i<link.size();i++) {br.com.caelum.restfulie.Link t = link.get(i); if(t.getRel().equals(rel)) links.add(t); } return links; }", newType));
newType.addMethod(CtNewMethod.make("public br.com.caelum.restfulie.Link getLink(String rel) { for(int i=0;i<link.size();i++) {br.com.caelum.restfulie.Link t = link.get(i); if(t.getRel().equals(rel)) return t; } return null; }", newType));
newType.addMethod(CtNewMethod.make("public boolean hasLink(String link) { return getLink(link)!=null; }", newType));
}
}