package org.kevoree.tools.annotator;
import javassist.*;
import org.kevoree.*;
import org.kevoree.Package;
import org.kevoree.annotation.Input;
import org.kevoree.annotation.Output;
import org.kevoree.annotation.Param;
import org.kevoree.api.*;
import org.kevoree.factory.KevoreeFactory;
import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.util.HashMap;
/**
* Created by duke on 23/01/2014.
* <p/>
* ModelBuilder in Pure Java, Need to be tested before going to production
*/
public class ModelBuilderHelper {
public static void deepMethods(CtClass clazz, KevoreeFactory factory, TypeDefinition currentTypeDefinition) throws ClassNotFoundException, NotFoundException {
for (CtMethod method : clazz.getDeclaredMethods()) {
for (Object annotation : method.getAnnotations()) {
if (annotation instanceof Input) {
Input annotationInput = (Input) annotation;
if (currentTypeDefinition instanceof org.kevoree.ComponentType) {
org.kevoree.ComponentType currentTypeDefinitionCT = (ComponentType) currentTypeDefinition;
PortTypeRef providedPortRef = factory.createPortTypeRef();
providedPortRef.setName(method.getName());
providedPortRef.setOptional(annotationInput.optional());
currentTypeDefinitionCT.addProvided(providedPortRef);
}
}
}
}
for (CtClass interfaceLoop : clazz.getInterfaces()) {
deepMethods(interfaceLoop, factory, currentTypeDefinition);
}
if (clazz.getSuperclass() != null) {
deepMethods(clazz.getSuperclass(), factory, currentTypeDefinition);
}
}
public static void deepFields(CtClass clazz, KevoreeFactory factory, TypeDefinition currentTypeDefinition) throws Exception {
for (CtField field : clazz.getDeclaredFields()) {
for (Object annotation : field.getAnnotations()) {
if (annotation instanceof org.kevoree.annotation.KevoreeInject) {
boolean checkType = false;
if (field.getType().getName().equals(ModelService.class.getName())) {
checkType = true;
}
if (field.getType().getName().equals(BootstrapService.class.getName())) {
checkType = true;
}
if (field.getType().getName().equals(KevScriptService.class.getName())) {
checkType = true;
}
if (field.getType().getName().equals(Context.class.getName())) {
checkType = true;
}
if (field.getType().getName().equals(ChannelContext.class.getName())) {
checkType = true;
}
if (!checkType) {
throw new Exception("KevoreeInject annotation is only suitable for following types : ModelService,BootstrapService,KevScriptService,Context,ChannelContext : currently found : " + field.getType().getName());
}
}
if (annotation instanceof Output) {
Output annotationOutput = (Output) annotation;
if (!field.getType().getName().equals(org.kevoree.api.Port.class.getName())) {
throw new Exception("Output port field must of type of " + org.kevoree.api.Port.class.getName());
}
if (currentTypeDefinition instanceof org.kevoree.ComponentType) {
org.kevoree.ComponentType currentTypeDefinitionComponentType = (ComponentType) currentTypeDefinition;
PortTypeRef requiredPortRef = factory.createPortTypeRef();
requiredPortRef.setName(field.getName());
requiredPortRef.setOptional(annotationOutput.optional());
currentTypeDefinitionComponentType.addRequired(requiredPortRef);
}
}
if (annotation instanceof Param) {
Param annotationParam = (Param) annotation;
boolean checkType = false;
if (field.getType().getName().equals(String.class.getName())) {
checkType = true;
}
if (field.getType().getName().equals(Float.class.getName())) {
checkType = true;
}
if (field.getType().getName().equals(Integer.class.getName())) {
checkType = true;
}
if (field.getType().getName().equals(Double.class.getName())) {
checkType = true;
}
if (field.getType().getName().equals(Boolean.class.getName())) {
checkType = true;
}
if (field.getType().getName().equals(Long.class.getName())) {
checkType = true;
}
if (!checkType) {
if (!field.getType().isPrimitive()) {
throw new Exception("Param annotation is only applicable on field of type String,Long,Double,Float,Integer, current " + field.getType().getName());
}
}
DictionaryAttribute dicAtt = factory.createDictionaryAttribute();
if (currentTypeDefinition.getDictionaryType() == null) {
currentTypeDefinition.setDictionaryType(factory.createDictionaryType());
}
dicAtt.setName(field.getName());
dicAtt.setDatatype(field.getType().getName());
dicAtt.setOptional(annotationParam.optional());
dicAtt.setFragmentDependant(annotationParam.fragmentDependent());
dicAtt.setDefaultValue(annotationParam.defaultValue());
currentTypeDefinition.getDictionaryType().addAttributes(dicAtt);
}
}
}
for (CtClass interfaceLoop : clazz.getInterfaces()) {
deepFields(interfaceLoop, factory, currentTypeDefinition);
}
if (clazz.getSuperclass() != null) {
deepFields(clazz.getSuperclass(), factory, currentTypeDefinition);
}
}
private static void checkParent(TypeDefinition current, CtClass clazz, CtClass originClazz, ContainerRoot root, KevoreeFactory factory) throws Exception {
if (clazz == null) {
return;
}
String name = clazz.getSimpleName();
String version = null;
String currentTypeName = null;
try {
for (Object an : clazz.getAnnotations()) {
String newMeta = metaClassName(an);
if (newMeta != null) {
if (currentTypeName != null) {
throw new Exception("A Java Class can't be mapped to several Kevoree TypeDefinition " + clazz.getName());
} else {
currentTypeName = newMeta;
}
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
if (currentTypeName != null) {
String endPath = clazz.getName().replace(".", File.separator) + ".class";
String baseURL = clazz.getURL().toString().replace(endPath, "");
/*
String manifest = baseURL + "META-INF" + File.separator + "MANIFEST.MF";
URL u2 = new URL(manifest);
System.out.println(u2.openStream().available());
*/
/*
if (version == null) {
File metaInf = new File(baseURL + "META-INF" + File.separator + "maven");
System.out.println(metaInf.exists());
if (metaInf.exists()) {
if (metaInf.listFiles().length > 0) {
File groupFile = metaInf.listFiles()[0];
}
}
} */
if (version == null) {
try {
String kevManifest = baseURL + "KEV-INF" + File.separator + "lib.json";
URL ukevManifest = new URL(kevManifest);
InputStream is = ukevManifest.openStream();
ContainerRoot libModel = (ContainerRoot) factory.createJSONLoader().loadModelFromStream(is).get(0);
HashMap<DeployUnit, Integer> links = new HashMap<DeployUnit, Integer>();
for (DeployUnit du : libModel.getDeployUnits()) {
if (!links.containsKey(du)) {
links.put(du, 0);
}
for (DeployUnit dul : du.getRequiredLibs()) {
if (!links.containsKey(dul)) {
links.put(dul, 0);
}
links.put(dul, links.get(dul) + 1);
}
}
//This current deploy unit should be the only one with no external references, tricky part
for (DeployUnit d : links.keySet()) {
if (links.get(d) == 0) {
version = d.getVersion();
}
}
is.close();
} catch (Exception e) {
//
}
}
if (version == null) {
version = current.getVersion();
}
TypeDefinition parent = getOrCreateTypeDefinition(name, version, root, factory, currentTypeName);
current.addSuperTypes(parent);
}
}
private static void processTypeDefinition(TypeDefinition td, DeployUnit du, CtClass clazz, ContainerRoot root, KevoreeFactory factory) throws Exception {
if (Modifier.isAbstract(clazz.getModifiers())) {
td.setAbstract(true);
} else {
td.setAbstract(false);
}
td.setBean(clazz.getName());
td.addDeployUnits(du);
try {
checkParent(td, clazz.getSuperclass(), clazz, root, factory);
} catch (NotFoundException e) {
e.printStackTrace();
}
try {
for (CtClass interf : clazz.getInterfaces()) {
checkParent(td, interf, clazz, root, factory);
}
} catch (NotFoundException e) {
e.printStackTrace();
}
}
public static TypeDefinition getOrCreateTypeDefinition(String name, String version, ContainerRoot root, KevoreeFactory factory, String typeName) {
String[] packages = name.split("\\.");
org.kevoree.Package pack = null;
for (int i = 0; i < packages.length - 1; i++) {
if (pack == null) {
pack = root.findPackagesByID(packages[i]);
if (pack == null) {
pack = (org.kevoree.Package) factory.createPackage().withName(packages[i]);
root.addPackages(pack);
}
} else {
Package packNew = pack.findPackagesByID(packages[i]);
if (packNew == null) {
packNew = (org.kevoree.Package) factory.createPackage().withName(packages[i]);
pack.addPackages(packNew);
}
pack = packNew;
}
}
//TODO generate find multi Key in KMF
for (TypeDefinition td : pack.getTypeDefinitions()) {
if (name.equals(td.getName()) && version.equals(td.getVersion())) {
return td;
}
}
TypeDefinition td = (TypeDefinition) factory.create(typeName);
td.setVersion(version);
td.setName(name);
pack.addTypeDefinitions(td);
return td;
}
public static void process(Object elem, CtClass clazz, KevoreeFactory factory, DeployUnit du, ContainerRoot root) throws Exception {
if (elem instanceof org.kevoree.annotation.GroupType) {
TypeDefinition td = getOrCreateTypeDefinition(clazz.getSimpleName(), du.getVersion(), root, factory, metaClassName(elem));
processTypeDefinition(td, du, clazz, root, factory);
deepFields(clazz, factory, td);
}
if (elem instanceof org.kevoree.annotation.ChannelType) {
TypeDefinition td = getOrCreateTypeDefinition(clazz.getSimpleName(), du.getVersion(), root, factory, metaClassName(elem));
processTypeDefinition(td, du, clazz, root, factory);
deepFields(clazz, factory, td);
}
if (elem instanceof org.kevoree.annotation.ComponentType) {
TypeDefinition td = getOrCreateTypeDefinition(clazz.getSimpleName(), du.getVersion(), root, factory, metaClassName(elem));
processTypeDefinition(td, du, clazz, root, factory);
deepFields(clazz, factory, td);
deepMethods(clazz, factory, td);
}
if (elem instanceof org.kevoree.annotation.NodeType) {
TypeDefinition td = getOrCreateTypeDefinition(clazz.getSimpleName(), du.getVersion(), root, factory, metaClassName(elem));
processTypeDefinition(td, du, clazz, root, factory);
deepFields(clazz, factory, td);
}
}
public static String metaClassName(Object elem) {
if (elem instanceof org.kevoree.annotation.GroupType) {
return org.kevoree.GroupType.class.getName();
}
if (elem instanceof org.kevoree.annotation.ChannelType) {
return org.kevoree.ChannelType.class.getName();
}
if (elem instanceof org.kevoree.annotation.ComponentType) {
return org.kevoree.ComponentType.class.getName();
}
if (elem instanceof org.kevoree.annotation.NodeType) {
return org.kevoree.NodeType.class.getName();
}
return null;
}
}