Package aQute.bnd.metatype

Source Code of aQute.bnd.metatype.OCDReader$Pair

package aQute.bnd.metatype;

import java.util.*;
import java.util.regex.*;

import org.osgi.service.metatype.annotations.*;

import aQute.bnd.osgi.*;
import aQute.bnd.osgi.Clazz.MethodDef;
import aQute.bnd.osgi.Descriptors.TypeRef;

public class OCDReader extends ClassDataCollector {
 
  private Analyzer  analyzer;
  private Clazz  clazz;
  @SuppressWarnings("unused")
  private boolean  inherit;
 
  private TypeRef name;

  private final Map<MethodDef, Pair> methods = new LinkedHashMap<MethodDef, Pair>();
  private MethodDef  method;
  private OCDDef ocd;


  OCDReader(Analyzer analyzer, Clazz clazz, boolean inherit) {
    this.analyzer = analyzer;
    this.clazz = clazz;
    this.inherit = inherit;
  }


     static OCDDef getOCDDef(Clazz c, Analyzer analyzer) throws Exception {
     boolean inherit = Processor.isTrue(analyzer.getProperty("-metatypeannotations-inherit"));
     OCDReader r = new OCDReader(analyzer, c, inherit);
     return r.getDef();
  }


  private OCDDef getDef() throws Exception {
    clazz.parseClassFileWithCollector(this);
    if (ocd != null) {
      doMethods();
    }
    return ocd;
  }


  @Override
  public void classBegin(int access, TypeRef name) {
    this.name = name;
  }

  @Override
  public void method(MethodDef defined) {
    methods.put(defined, null);
    method = defined;
  }
 
  static Pattern  COLLECTION  = Pattern.compile("(.*(Collection|Set|List|Queue|Stack|Deque))<(L.+;)>");
  private void doMethods() throws Exception {
    for (Map.Entry<MethodDef,Pair> entry: methods.entrySet()) {
      MethodDef defined = entry.getKey();
      ADDef ad = new ADDef();
      ocd.attributes.add(ad);
      ad.id = fixup(defined.getName());
      ad.name = space(defined.getName());
      ad.description = "";
      String rtype = defined.getGenericReturnType();
      ad.type = getType(rtype);
      if (rtype.endsWith("[]")) {
        ad.cardinality = Integer.MAX_VALUE;
        rtype = rtype.substring(0, rtype.length() - 2);
      }
      if (rtype.indexOf('<') > 0) {
        if (ad.cardinality != 0)
          analyzer.error(
              "AD for %s.%s uses an array of collections in return type (%s), Metatype allows either Vector or array",
              clazz.getClassName().getFQN(), defined.getName(), defined.getType().getFQN());
        Matcher m = COLLECTION.matcher(rtype);
        if (m.matches()) {
          rtype = Clazz.objectDescriptorToFQN(m.group(3));
          ad.cardinality = Integer.MIN_VALUE;
        }
      }

      ad.required = true;
      TypeRef typeRef = analyzer.getTypeRefFromFQN(rtype);
      try {
        Clazz c = analyzer.findClass(typeRef);
        if (c != null && c.isEnum()) {
          parseOptionValues(c, ad.options);
        }
      }
      catch (Exception e) {
        analyzer.error(
            "AD for %s.%s Can not parse option values from type (%s), %s",
            clazz.getClassName().getFQN(), defined.getName(), defined.getType().getFQN(), e.getMessage());
      }
      if (entry.getValue() != null) {
        doAD(ad, entry.getValue());
      }
    }
  }

  private void doAD(ADDef ad, Pair pair) throws Exception {
    AttributeDefinition a = pair.getAd();
    Annotation annotation = pair.getA();

    if (a.name() != null) {
      ad.name = a.name();
    }
    ad.description = a.description();
    if (a.type() != null) {
      ad.type = a.type().toString();
    }
    ad.cardinality = a.cardinality();
    ad.max = a.max();
    ad.min = a.min();
    ad.defaults = a.defaultValue();
    if (annotation.get("required") != null) {
      ad.required = a.required();
    }
    if (annotation.get("options") != null) {
      ad.options.clear();
      for (Object o : (Object[])annotation.get("options")) {
        Option opt = ((Annotation)o).getAnnotation();
        ad.options.add(new OptionDef(opt.label(), opt.value()));
      }
    }

  }

  private static final Pattern p = Pattern.compile("(\\$\\$)|(\\$)|(__)|(_)");
   
    static String fixup(String name)
    {
        Matcher m = p.matcher(name);
        StringBuffer b = new StringBuffer();
        while (m.find())
        {
            String replacement = "";//null;
            if (m.group(1) != null) replacement = "\\$";
            if (m.group(2) != null) replacement = "";
            if (m.group(3) != null) replacement = "_";
            if (m.group(4) != null) replacement = ".";
           
            m.appendReplacement(b, replacement);
        }
        m.appendTail(b);
        return b.toString();
    }
   
    static String space(String name) {
      return Clazz.unCamel(name);//TODO I don't understand "spaces" rule in spec 5.2
    }

  String getType(String rtype) {
    if (rtype.endsWith("[]")) {
      rtype = rtype.substring(0, rtype.length() - 2);
      if (rtype.endsWith("[]"))
        throw new IllegalArgumentException("Can only handle array of depth one");
    }

    if ("boolean".equals(rtype) || Boolean.class.getName().equals(rtype))
      return AttributeType.BOOLEAN.toString();
    else if ("byte".equals(rtype) || Byte.class.getName().equals(rtype))
      return AttributeType.BYTE.toString();
    else if ("char".equals(rtype) || Character.class.getName().equals(rtype))
      return AttributeType.CHARACTER.toString();
    else if ("short".equals(rtype) || Short.class.getName().equals(rtype))
      return AttributeType.SHORT.toString();
    else if ("int".equals(rtype) || Integer.class.getName().equals(rtype))
      return AttributeType.INTEGER.toString();
    else if ("long".equals(rtype) || Long.class.getName().equals(rtype))
      return AttributeType.LONG.toString();
    else if ("float".equals(rtype) || Float.class.getName().equals(rtype))
      return AttributeType.FLOAT.toString();
    else if ("double".equals(rtype) || Double.class.getName().equals(rtype))
      return AttributeType.DOUBLE.toString();
    else
      return AttributeType.STRING.toString();
  }
   
  private void parseOptionValues(Clazz c, final List<OptionDef> options) throws Exception {

    c.parseClassFileWithCollector(new ClassDataCollector() {
      @Override
      public void field(Clazz.FieldDef def) {
        if (def.isEnum()) {
          OptionDef o = new OptionDef(def.getName(), def.getName()); //TODO first arg should be "toString()" result
          options.add(o);
        }
      }
    });
  }

  private final static class Pair {
    private final AttributeDefinition ad;
    private final Annotation a;
   
    public Pair(AttributeDefinition ad, Annotation a) {
      this.ad = ad;
      this.a = a;
    }

    AttributeDefinition getAd() {
      return ad;
    }

    Annotation getA() {
      return a;
    }
       
  }
 
    @Override
  public void annotation(Annotation annotation) throws Exception {
    try {
      java.lang.annotation.Annotation a = annotation.getAnnotation();
      if (a instanceof ObjectClassDefinition)
        doOCD((ObjectClassDefinition) a, annotation);
      else if (a instanceof AttributeDefinition)
        methods.put(method, new Pair((AttributeDefinition)a, annotation));
    }
    catch (Exception e) {
      e.printStackTrace();
      analyzer.error("During generation of a component on class %s, exception %s", clazz, e);
    }
  }

  private void doOCD(ObjectClassDefinition o, Annotation annotation) {
    ocd = new OCDDef();
    ocd.id = o.id() == null? name.getFQN(): o.id();
    ocd.name = o.name() == null? space(ocd.id): o.name()
    ocd.description = o.description() == null? "": o.description();
    ocd.localization = o.localization() == null? "OSGI-INF/l10n/" + name.getFQN(): o.localization();
    if (annotation.get("pid") != null ) {
      String[] pids = o.pid();
      designates(pids, false);
    }
    if (annotation.get("factoryPid") != null ) {
      String[] pids = o.factoryPid();
      designates(pids, true);
    }
    if (annotation.get("icon") != null) {
      Icon[] icons = o.icon();
      for (Icon icon: icons) {
        ocd.icons.add(new IconDef(icon.resource(), icon.size()));
      }
    }
   
  }

  private void designates(String[] pids, boolean factory) {
    for (String pid: pids) {
      ocd.designates.add(new DesignateDef(ocd.id, pid, factory));
    }   
  }




}
TOP

Related Classes of aQute.bnd.metatype.OCDReader$Pair

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.