package org.kevoree.tools.mavenplugin.util; import javassist.*; import org.apache.commons.codec.digest.DigestUtils; import org.kevoree.*; import org.kevoree.annotation.Input; import org.kevoree.annotation.Output; import org.kevoree.annotation.Param; import org.kevoree.api.*; import org.kevoree.api.Port; import org.kevoree.factory.KevoreeFactory; /** * Created by duke on 23/01/2014. * <p/> */ public class ModelBuilderHelper { public static void deepMethods(CtClass clazz, KevoreeFactory factory, TypeDefinition currentTypeDefinition) throws Exception { for (CtMethod method : clazz.getDeclaredMethods()) { for (Object annotation : method.getAnnotations()) { if (annotation instanceof Input) { Input annotationInput = (Input) annotation; if (currentTypeDefinition instanceof ComponentType) { ComponentType currentTypeDefinitionCT = (ComponentType) currentTypeDefinition; PortTypeRef providedPortRef = factory.createPortTypeRef(); providedPortRef.setName(method.getName()); try { providedPortRef.setOptional(annotationInput.optional()); } catch (Exception e) { providedPortRef.setOptional(true); } providedPortRef.setNoDependency(true); currentTypeDefinitionCT.addProvided(providedPortRef); } } if (annotation instanceof Param && (method.getName().startsWith("set") || method.getName().startsWith("get"))) { boolean checkType = false; String cleanedName = method.getName().substring(3); cleanedName = cleanedName.substring(0, 1).toLowerCase() + cleanedName.substring(1); Param annotationParam = (Param) annotation; DataType dataType = null; if (method.getReturnType().getName().equals(String.class.getName())) { checkType = true; dataType = DataType.STRING; } if (method.getReturnType().getName().equals(Float.class.getName()) || method.getReturnType().getName().equals("float")) { checkType = true; dataType = DataType.FLOAT; } if (method.getReturnType().getName().equals(Integer.class.getName()) || method.getReturnType().getName().equals("int")) { checkType = true; dataType = DataType.INT; } if (method.getReturnType().getName().equals(Double.class.getName()) || method.getReturnType().getName().equals("double")) { checkType = true; dataType = DataType.DOUBLE; } if (method.getReturnType().getName().equals(Boolean.class.getName()) || method.getReturnType().getName().equals("boolean")) { checkType = true; dataType = DataType.BOOLEAN; } if (method.getReturnType().getName().equals(Long.class.getName()) || method.getReturnType().getName().equals("long")) { checkType = true; dataType = DataType.LONG; } if (method.getReturnType().getName().equals(Byte.class.getName()) || method.getReturnType().getName().equals(byte.class.getName()) || method.getReturnType().getName().equals("byte")) { checkType = true; dataType = DataType.BYTE; } if (method.getReturnType().getName().equals(char.class.getName()) || method.getReturnType().getName().equals("char")) { checkType = true; dataType = DataType.CHAR; } if (method.getReturnType().getName().equals(Short.class.getName()) || method.getReturnType().getName().equals("short")) { checkType = true; dataType = DataType.SHORT; } if (!checkType) { if (!method.getReturnType().isPrimitive()) { throw new Exception("Param annotation is only applicable on field of type String,Long,Double,Float,Integer, current " + method.getReturnType().getName()); } } DictionaryAttribute dicAtt = factory.createDictionaryAttribute(); if (currentTypeDefinition.getDictionaryType() == null) { currentTypeDefinition.setDictionaryType(factory.createDictionaryType().withGenerated_KMF_ID("0.0")); } dicAtt.setName(cleanedName); dicAtt.setDatatype(dataType); try { dicAtt.setOptional(annotationParam.optional()); } catch (Exception e) { dicAtt.setOptional(true); } try { dicAtt.setFragmentDependant(annotationParam.fragmentDependent()); } catch (Exception e) { dicAtt.setFragmentDependant(false); } try { dicAtt.setDefaultValue(annotationParam.defaultValue()); } catch (Exception e) { dicAtt.setDefaultValue(""); } currentTypeDefinition.getDictionaryType().addAttributes(dicAtt); } } } 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()) { try { 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; } else if (field.getType().getName().equals(BootstrapService.class.getName())) { checkType = true; } else if (field.getType().getName().equals(KevScriptService.class.getName())) { checkType = true; } else if (field.getType().getName().equals(Context.class.getName())) { checkType = true; } else if (field.getType().getName().equals(ChannelContext.class.getName())) { checkType = true; } else if (field.getType().getName().equals(PlatformService.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(Port.class.getName())) { throw new Exception("Output port field must of type of " + Port.class.getName()); } if (currentTypeDefinition instanceof ComponentType) { ComponentType currentTypeDefinitionComponentType = (ComponentType) currentTypeDefinition; PortTypeRef requiredPortRef = factory.createPortTypeRef(); requiredPortRef.setName(field.getName()); try { requiredPortRef.setOptional(annotationOutput.optional()); } catch (Exception e) { requiredPortRef.setOptional(true); } requiredPortRef.setNoDependency(true); currentTypeDefinitionComponentType.addRequired(requiredPortRef); } } if (annotation instanceof Param) { Param annotationParam = (Param) annotation; DataType dataType = null; boolean checkType = false; if (field.getType().getName().equals(String.class.getName())) { checkType = true; dataType = DataType.STRING; } if (field.getType().getName().equals(Float.class.getName()) || field.getType().getName().equals("float")) { checkType = true; dataType = DataType.FLOAT; } if (field.getType().getName().equals(Integer.class.getName()) || field.getType().getName().equals("int")) { checkType = true; dataType = DataType.INT; } if (field.getType().getName().equals(Double.class.getName()) || field.getType().getName().equals("double")) { checkType = true; dataType = DataType.DOUBLE; } if (field.getType().getName().equals(Boolean.class.getName()) || field.getType().getName().equals("boolean")) { checkType = true; dataType = DataType.BOOLEAN; } if (field.getType().getName().equals(Long.class.getName()) || field.getType().getName().equals("long")) { checkType = true; dataType = DataType.LONG; } if (field.getType().getName().equals(Short.class.getName()) || field.getType().getName().equals("short")) { checkType = true; dataType = DataType.SHORT; } if (field.getType().getName().equals(char.class.getName()) || field.getType().getName().equals("char")) { checkType = true; dataType = DataType.CHAR; } if (field.getType().getName().equals(byte.class.getName()) || field.getType().getName().equals("byte") || field.getType().getName().equals(Byte.class.getName())) { checkType = true; dataType = DataType.BYTE; } 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().withGenerated_KMF_ID("0.0")); } dicAtt.setName(field.getName()); dicAtt.setDatatype(dataType); try { dicAtt.setOptional(annotationParam.optional()); } catch (Exception e) { dicAtt.setOptional(true); } try { dicAtt.setFragmentDependant(annotationParam.fragmentDependent()); } catch (Exception e) { dicAtt.setFragmentDependant(false); } try { dicAtt.setDefaultValue(annotationParam.defaultValue()); } catch (Exception e) { dicAtt.setDefaultValue(null); } currentTypeDefinition.getDictionaryType().setGenerated_KMF_ID("0.0"); currentTypeDefinition.getDictionaryType().addAttributes(dicAtt); } } } catch (ClassNotFoundException ignore) {} } 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.getName(); // 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) { // final HashMap<DeployUnit, Integer> links = new HashMap<DeployUnit, Integer>(); // // root.deepVisitContained(new ModelVisitor() { // @Override // public void visit(@NotNull KMFContainer kmfContainer, @NotNull String s, @NotNull KMFContainer kmfContainer2) { // if (kmfContainer instanceof DeployUnit) { // DeployUnit du = (DeployUnit) kmfContainer; // 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(); // } // } // if (version == null) { // version = current.getVersion(); // } // TypeDefinition parent = getOrCreateTypeDefinition(name, version, root, factory, (org.kevoree.Package) current.eContainer(), 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); } final Value javaClazz = factory.createValue(); javaClazz.setName("class:" + td.getName() + ":" + td.getVersion()); javaClazz.setValue(clazz.getName()); du.addFilters(javaClazz); 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(final String name, final Long version, final ContainerRoot root, final KevoreeFactory factory, final org.kevoree.Package pkg, final String typeName) { final TypeDefinition foundTD = pkg.findTypeDefinitionsByNameVersion(name, String.valueOf(version)); if (foundTD != null) { return foundTD; } else { final TypeDefinition td = (TypeDefinition) factory.create(typeName); td.setVersion(String.valueOf(version)); td.setName(name); td.setDictionaryType(factory.createDictionaryType().withGenerated_KMF_ID("0.0")); pkg.addTypeDefinitions(td); return td; } } public static void process(Object elem, CtClass clazz, KevoreeFactory factory, DeployUnit du, ContainerRoot root) throws Exception { TypeDefinition td = null; String descVal = null; if (elem instanceof org.kevoree.annotation.GroupType) { td = getOrCreateTypeDefinition( clazz.getSimpleName(), ((org.kevoree.annotation.GroupType) elem).version(), root, factory, (org.kevoree.Package) du.eContainer(), metaClassName(elem)); descVal = ((org.kevoree.annotation.GroupType) elem).description(); } else if (elem instanceof org.kevoree.annotation.ChannelType) { td = getOrCreateTypeDefinition( clazz.getSimpleName(), ((org.kevoree.annotation.ChannelType) elem).version(), root, factory, (org.kevoree.Package) du.eContainer(), metaClassName(elem)); descVal = ((org.kevoree.annotation.ChannelType) elem).description(); } else if (elem instanceof org.kevoree.annotation.ComponentType) { td = getOrCreateTypeDefinition( clazz.getSimpleName(), ((org.kevoree.annotation.ComponentType) elem).version(), root, factory, (org.kevoree.Package) du.eContainer(), metaClassName(elem)); descVal = ((org.kevoree.annotation.ComponentType) elem).description(); } else if (elem instanceof org.kevoree.annotation.NodeType) { td = getOrCreateTypeDefinition( clazz.getSimpleName(), ((org.kevoree.annotation.NodeType) elem).version(), root, factory, (org.kevoree.Package) du.eContainer(), metaClassName(elem)); descVal = ((org.kevoree.annotation.NodeType) elem).description(); } if (td != null) { if (descVal != null && !descVal.isEmpty()) { Value desc = factory.createValue(); desc.setName("description"); desc.setValue(descVal); td.addMetaData(desc); } processTypeDefinition(td, du, clazz, root, factory); deepFields(clazz, factory, td); deepMethods(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; } public static String createKey(String namespace, String name, String version, String append) { String data = namespace + "/" + name + "/" + version; if (append != null && !append.isEmpty()) { data += "/" + append; } return DigestUtils.md5Hex(data); } }