Example #1
0
 private DesignateDef getDef() throws Exception {
   clazz.parseClassFileWithCollector(this);
   if (pid != null && designate != null) {
     if (pids != null && pids.length > 1) {
       analyzer.error(
           "DS Component %s specifies multiple pids %s, and a Designate which requires exactly one pid",
           clazz.getClassName().getFQN(), Arrays.asList(pids));
       return null;
     }
     TypeRef ocdClass = designate.get("ocd");
     // ocdClass = ocdClass.substring(1, ocdClass.length() - 1);
     OCDDef ocd = classToOCDMap.get(ocdClass);
     if (ocd == null) {
       analyzer.error(
           "DS Component %s specifies ocd class %s which cannot be found; known classes %s",
           clazz.getClassName().getFQN(), ocdClass, classToOCDMap.keySet());
       return null;
     }
     String id = ocd.id;
     boolean factoryPid = Boolean.TRUE == designate.get("factory");
     if (def == null) def = new DesignateDef(finder);
     def.ocdRef = id;
     def.pid = pid;
     def.factory = factoryPid;
     ocd.designates.add(def);
     return def;
   }
   return null;
 }
Example #2
0
 private void parseExtends(Clazz clazz) {
   TypeRef[] inherits = clazz.getInterfaces();
   if (inherits != null) {
     if (analyzed == null) {
       analyzed = new HashSet<TypeRef>();
     }
     for (TypeRef typeRef : inherits) {
       if (!typeRef.isJava() && analyzed.add(typeRef)) {
         try {
           Clazz inherit = analyzer.findClass(typeRef);
           if (inherit != null) {
             inherit.parseClassFileWithCollector(this);
             parseExtends(inherit);
           } else {
             analyzer.error(
                 "Could not obtain super class %s of class %s",
                 typeRef.getFQN(), clazz.getClassName().getFQN());
           }
         } catch (Exception e) {
           analyzer.error(
               "Could not obtain super class %s of class %s; exception %s",
               typeRef.getFQN(), clazz.getClassName().getFQN(), e.getMessage());
         }
       }
     }
   }
 }
Example #3
0
 private boolean acceptableType(String rtype) {
   TypeRef ref = analyzer.getTypeRefFromFQN(rtype);
   try {
     Clazz returnType = analyzer.findClass(ref);
     if (returnType.isEnum()) {
       return true;
     }
     // TODO check this is true for interfaces and annotations
     if (!returnType.isAbstract()
         || (returnType.isInterface() && options.contains(Options.nested))) {
       return true;
     }
     if (!returnType.isInterface()) {
       analyzer.error("Abstract classes not allowed as interface method return values: %s", rtype);
     } else {
       analyzer.error("Nested metatype only allowed with option: nested type %s", rtype);
     }
     return false;
   } catch (Exception e) {
     analyzer.error(
         "could not examine class for return type %s, exception message: %s",
         rtype, e.getMessage());
     return false;
   }
 }
  /**
   * All the BND magic happens here.
   *
   * @param jarInputStream On what to operate.
   * @param instructions BND instructions from user API
   * @param symbolicName Mandatory Header. In case user does not set it.
   * @return Bundle Jar Stream
   * @throws Exception Problems go here
   */
  private InputStream createBundle(
      InputStream jarInputStream, Properties instructions, String symbolicName) throws Exception {
    NullArgumentException.validateNotNull(jarInputStream, "Jar URL");
    NullArgumentException.validateNotNull(instructions, "Instructions");
    NullArgumentException.validateNotEmpty(symbolicName, "Jar info");

    final Jar jar = new Jar("dot", sink(jarInputStream));

    final Properties properties = new Properties();
    properties.putAll(instructions);

    final Analyzer analyzer = new Analyzer();
    analyzer.setJar(jar);
    analyzer.setProperties(properties);

    // throw away already existing headers that we overwrite:

    analyzer.mergeManifest(jar.getManifest());

    checkMandatoryProperties(analyzer, jar, symbolicName);
    Manifest manifest = analyzer.calcManifest();
    jar.setManifest(manifest);

    return createInputStream(jar);
  }
Example #5
0
 public static void testAbsentIncludes() throws IOException {
   Analyzer analyzer = new Analyzer();
   analyzer.setBase(IO.getFile("src/test"));
   Properties p = new Properties();
   p.put("-include", "-iamnotthere.txt");
   analyzer.setProperties(p);
   System.err.println(analyzer.getErrors());
   assertEquals(0, analyzer.getErrors().size());
 }
Example #6
0
 /** Test url includes */
 public static void testUrlIncludes2() throws IOException {
   Analyzer a = new Analyzer();
   Properties p = new Properties();
   p.setProperty("a", "1");
   p.setProperty("-include", "jar:file:jar/osgi.jar/!/META-INF/MANIFEST.MF");
   a.setProperties(p);
   assertEquals("1", a.getProperty("a"));
   assertEquals("osgi", a.getProperty("Bundle-SymbolicName"));
 }
Example #7
0
 /** Test url includes props: a\ b\ c\ d last-props: end */
 public static void testUrlIncludes() throws IOException {
   Analyzer a = new Analyzer();
   Properties p = new Properties();
   p.setProperty("a", "1");
   p.setProperty("-include", "file:src/test/includeheadertest.prop");
   a.setProperties(p);
   assertEquals("1", a.getProperty("a"));
   assertEquals("end", a.getProperty("last-props"));
   assertEquals("abcd", a.getProperty("props"));
 }
Example #8
0
  /**
   * Called to prepare. If will look for any errors or inconsistencies in the setup.
   *
   * @param analyzer the analyzer to report errors and create references
   * @throws Exception
   */
  void prepare(Analyzer analyzer) throws Exception {

    prepareVersion(analyzer);

    if (implementation == null) {
      analyzer.error("No Implementation defined for component " + name);
      return;
    }

    analyzer.referTo(implementation);

    if (name == null) name = implementation.getFQN();

    if (service != null && service.length > 0) {
      for (TypeRef interfaceName : service) analyzer.referTo(interfaceName);
    } else if (scope != null && scope != ServiceScope.BUNDLE)
      analyzer.warning(
          "The servicefactory:=true directive is set but no service is provided, ignoring it");

    for (Map.Entry<String, List<String>> kvs : property.entrySet()) {
      Tag property = new Tag("property");
      String name = kvs.getKey();
      String type = propertyType.get(name);

      property.addAttribute("name", name);
      if (type != null) {
        property.addAttribute("type", type);
      }
      if (kvs.getValue().size() == 1) {
        String value = kvs.getValue().get(0);
        value = check(type, value, analyzer);
        property.addAttribute("value", value);
      } else {
        StringBuilder sb = new StringBuilder();

        String del = "";
        for (String v : kvs.getValue()) {
          if (v == MARKER) {
            continue;
          }
          sb.append(del);
          v = check(type, v, analyzer);
          sb.append(v);
          del = "\n";
        }
        property.addContent(sb.toString());
      }
      propertyTags.add(property);
    }
  }
Example #9
0
 public static void testIncludeHeader() throws IOException {
   Analyzer analyzer = new Analyzer();
   analyzer.setBase(IO.getFile("src/test"));
   Properties p = new Properties();
   p.put("a", "1");
   p.put("-include", "includeheadertest.mf, includeheadertest.prop");
   analyzer.setProperties(p);
   System.err.println(analyzer.getProperties());
   assertEquals("1", analyzer.getProperty("a"));
   assertEquals("end", analyzer.getProperty("last-props"));
   assertEquals("end", analyzer.getProperty("last-manifest"));
   assertEquals("abcd", analyzer.getProperty("manifest"));
   assertEquals("abcd", analyzer.getProperty("props"));
   assertEquals("1", analyzer.getProperty("test"));
 }
Example #10
0
  /**
   * Prepare the reference, will check for any errors. @param analyzer the analyzer to report errors
   * to. @throws Exception
   */
  public void prepare(Analyzer analyzer) throws Exception {
    if (name == null) analyzer.error("No name for a reference");

    if ((updated != null && !updated.equals("-")) || policyOption != null)
      updateVersion(AnnotationReader.V1_2);

    if (target != null) {
      String error = Verifier.validateFilter(target);
      if (error != null) analyzer.error("Invalid target filter %s for %s", target, name);
    }

    if (service == null) analyzer.error("No interface specified on %s", name);

    if (scope != null || field != null) updateVersion(AnnotationReader.V1_3);
  }
Example #11
0
  AttributeType getType(String rtype) {
    if (rtype.endsWith("[]")) {
      analyzer.error("Can only handle array of depth one field , nested type %s", rtype);
      return null;
    }

    if ("boolean".equals(rtype) || Boolean.class.getName().equals(rtype))
      return AttributeType.BOOLEAN;
    else if ("byte".equals(rtype) || Byte.class.getName().equals(rtype)) return AttributeType.BYTE;
    else if ("char".equals(rtype) || Character.class.getName().equals(rtype))
      return AttributeType.CHARACTER;
    else if ("short".equals(rtype) || Short.class.getName().equals(rtype))
      return AttributeType.SHORT;
    else if ("int".equals(rtype) || Integer.class.getName().equals(rtype))
      return AttributeType.INTEGER;
    else if ("long".equals(rtype) || Long.class.getName().equals(rtype)) return AttributeType.LONG;
    else if ("float".equals(rtype) || Float.class.getName().equals(rtype))
      return AttributeType.FLOAT;
    else if ("double".equals(rtype) || Double.class.getName().equals(rtype))
      return AttributeType.DOUBLE;
    else if (String.class.getName().equals(rtype)
        || Class.class.getName().equals(rtype)
        || acceptableType(rtype)) return AttributeType.STRING;
    else {
      return null;
    }
  }
Example #12
0
 private void doOCD(ObjectClassDefinition o, Annotation annotation) {
   if (topLevel) {
     if (clazz.isInterface()) {
       if (ocd == null) ocd = new OCDDef(finder);
       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()));
         }
       }
     } else {
       analyzer.error(
           "ObjectClassDefinition applied to non-interface, non-annotation class %s", clazz);
     }
   }
 }
  /** Created a JAR that is a bundle and that contains its dependencies */
  @Override
  public Jar executable() throws Exception {
    Collection<String> bsns = getProject().getBsns();
    if (bsns.size() != 1)
      throw new IllegalArgumentException(
          "Can only handle a single bsn for a run configuration " + bsns);
    String bsn = bsns.iterator().next();

    Jar jar = new Jar(bsn);
    String path = "aQute/remote/embedded/activator/EmbeddedActivator.class";
    URLResource resource = new URLResource(getClass().getClassLoader().getResource(path));
    jar.putResource("aQute/remote/embedded/activator/EmbeddedActivator.class", resource);

    Collection<Container> rb = getProject().getRunbundles();
    rb = Container.flatten(rb);
    Attrs attrs = new Attrs();

    for (Container c : rb) {
      if (c.getError() != null) {
        getProject().error("invalid runbundle %s", c);
      } else {
        File f = c.getFile();
        String tbsn = c.getBundleSymbolicName();
        String version = c.getVersion();
        if (version == null || !Version.isVersion(version))
          getProject()
              .warning("The version of embedded bundle %s does not have a proper version", c);

        jar.putResource("jar/" + c.getBundleSymbolicName() + ".jar", new FileResource(f));

        attrs.put(tbsn, version);
      }
    }

    Analyzer a = new Analyzer(getProject());
    a.setJar(jar);

    a.setBundleActivator(EmbeddedActivator.class.getName());
    a.setProperty("Bnd-Embedded", attrs.toString().replace(';', ','));
    Manifest manifest = a.calcManifest();
    jar.setManifest(manifest);
    getProject().getInfo(a);
    return jar;
  }
  /**
   * Check if mandatory properties are present, otherwise generate default.
   *
   * @param analyzer bnd analyzer
   * @param jar bnd jar
   * @param symbolicName bundle symbolic name
   */
  private void checkMandatoryProperties(
      final Analyzer analyzer, final Jar jar, final String symbolicName) {
    final String importPackage = analyzer.getProperty(Analyzer.IMPORT_PACKAGE);

    // imports must be generated for sure. Thats why we use BND at all.

    // if( importPackage == null || importPackage.trim().length() == 0 ) {
    analyzer.setProperty(Analyzer.IMPORT_PACKAGE, "*");
    // }

    // automatic export:
    final String exportPackage = analyzer.getProperty(Analyzer.EXPORT_PACKAGE);
    if (exportPackage == null || exportPackage.trim().length() == 0) {
      //  analyzer.setProperty( Analyzer.EXPORT_PACKAGE, analyzer.calculateExportsFromContents( jar
      // ) );
    }
    final String localSymbolicName =
        analyzer.getProperty(Analyzer.BUNDLE_SYMBOLICNAME, symbolicName);
    analyzer.setProperty(Analyzer.BUNDLE_SYMBOLICNAME, generateSymbolicName(localSymbolicName));
  }
Example #15
0
 public static void testInvalidCaseForHeader() throws Exception {
   Properties p = new Properties();
   p.put("Export-package", "org.apache.mina.*");
   p.put("Bundle-Classpath", ".");
   Analyzer analyzer = new Analyzer();
   analyzer.setProperties(p);
   analyzer.getProperties();
   System.err.println("Errors   " + analyzer.getErrors());
   System.err.println("Warnings " + analyzer.getWarnings());
   assertEquals(0, analyzer.getErrors().size());
   assertEquals(2, analyzer.getWarnings().size());
 }
Example #16
0
 private boolean identifiableCollection(String type, boolean intface, boolean topLevel) {
   try {
     Clazz clazz = analyzer.findClass(analyzer.getTypeRefFromFQN(type));
     if (clazz != null
         && (!topLevel || !clazz.isAbstract())
         && ((intface && clazz.isInterface()) ^ clazz.hasPublicNoArgsConstructor())) {
       TypeRef[] intfs = clazz.getInterfaces();
       if (intfs != null) {
         for (TypeRef intf : intfs) {
           if (COLLECTION.matcher(intf.getFQN()).matches()
               || identifiableCollection(intf.getFQN(), true, false)) {
             return true;
           }
         }
       }
       TypeRef ext = clazz.getSuper();
       return ext != null && identifiableCollection(ext.getFQN(), false, false);
     }
   } catch (Exception e) {
     return false;
   }
   return false;
 }
Example #17
0
  private String check(String type, String v, Analyzer analyzer) {
    if (type == null) return v;

    try {
      if (type.equals("Char")) type = "Character";

      Class<?> c = Class.forName("java.lang." + type);
      if (c == String.class) return v;

      v = v.trim();
      if (c == Character.class) c = Integer.class;
      Method m = c.getMethod("valueOf", String.class);
      m.invoke(null, v);
    } catch (ClassNotFoundException e) {
      analyzer.error("Invalid data type %s", type);
    } catch (NoSuchMethodException e) {
      analyzer.error("Cannot convert data %s to type %s", v, type);
    } catch (NumberFormatException e) {
      analyzer.error("Not a valid number %s for %s, %s", v, type, e.getMessage());
    } catch (Exception e) {
      analyzer.error("Cannot convert data %s to type %s", v, type);
    }
    return v;
  }
Example #18
0
 @Override
 public void annotation(Annotation annotation) throws Exception {
   try {
     java.lang.annotation.Annotation a = annotation.getAnnotation();
     if (a instanceof Designate) designate = annotation;
     else if (a instanceof Component) {
       doComponent(a);
     } else {
       XMLAttribute xmlAttr = finder.getXMLAttribute(annotation);
       if (xmlAttr != null) {
         doXmlAttribute(annotation, xmlAttr);
       }
     }
   } catch (Exception e) {
     e.printStackTrace();
     analyzer.error("During generation of a component on class %s, exception %s", clazz, e);
   }
 }
Example #19
0
 @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) {
       current.ad = (AttributeDefinition) a;
       current.a = annotation;
     } else {
       XMLAttribute xmlAttr = finder.getXMLAttribute(annotation);
       if (xmlAttr != null) {
         doXmlAttribute(annotation, xmlAttr);
       }
     }
   } catch (Exception e) {
     e.printStackTrace();
     analyzer.error("During generation of a component on class %s, exception %s", clazz, e);
   }
 }
Example #20
0
 public static void testIncludeWithProperty() throws IOException {
   File home = new File(System.getProperty("user.home"));
   File include = new File(home, "includeheadertest.txt");
   try {
     FileOutputStream fw = new FileOutputStream(include);
     fw.write("IncludeHeaderTest: yes\n\r".getBytes());
     fw.write("a: 2\n\r".getBytes());
     fw.write("b: ${a}\n\r".getBytes());
     fw.close();
     Analyzer analyzer = new Analyzer();
     analyzer.setBase(IO.getFile("src/test"));
     Properties p = new Properties();
     p.put("a", "1");
     p.put("-include", "-iamnotthere.txt, ${user.home}/includeheadertest.txt");
     analyzer.setProperties(p);
     String value = analyzer.getProperty("IncludeHeaderTest");
     assertEquals("yes", value);
     assertEquals("2", analyzer.getProperty("a"));
     assertEquals("2", analyzer.getProperty("b"));
     assertEquals(0, analyzer.getErrors().size());
   } finally {
     include.delete();
   }
 }
  private Manifest _calculateManifest(URL url, Manifest manifest) {
    Analyzer analyzer = new Analyzer();

    Jar jar = null;

    try {
      URLConnection urlConnection = url.openConnection();

      String fileName = url.getFile();

      if (urlConnection instanceof JarURLConnection) {
        JarURLConnection jarURLConnection = (JarURLConnection) urlConnection;

        URL jarFileURL = jarURLConnection.getJarFileURL();

        fileName = jarFileURL.getFile();
      }

      File file = new File(fileName);

      if (!file.exists() || !file.canRead()) {
        return manifest;
      }

      fileName = file.getName();

      analyzer.setJar(new Jar(fileName, file));

      jar = analyzer.getJar();

      String bundleSymbolicName = fileName;

      Matcher matcher = _bundleSymbolicNamePattern.matcher(bundleSymbolicName);

      if (matcher.matches()) {
        bundleSymbolicName = matcher.group(1);
      }

      analyzer.setProperty(Analyzer.BUNDLE_SYMBOLICNAME, bundleSymbolicName);

      String exportPackage = _calculateExportPackage(jar);

      analyzer.setProperty(Analyzer.EXPORT_PACKAGE, exportPackage);

      analyzer.mergeManifest(manifest);

      String bundleVersion = analyzer.getProperty(Analyzer.BUNDLE_VERSION);

      if (bundleVersion != null) {
        bundleVersion = Builder.cleanupVersion(bundleVersion);

        analyzer.setProperty(Analyzer.BUNDLE_VERSION, bundleVersion);
      }

      return analyzer.calcManifest();
    } catch (Exception e) {
      _log.error(e, e);

      return manifest;
    } finally {
      if (jar != null) {
        jar.close();
      }

      analyzer.close();
    }
  }
Example #22
0
 public static void testTopBottom() throws Exception {
   Analyzer analyzer = new Analyzer();
   analyzer.setProperties(IO.getFile("src/test/include.bnd/top.bnd"));
   assertEquals("0.0.257", analyzer.getProperty("Bundle-Version"));
 }
Example #23
0
  private void doMethods() throws Exception {
    for (Map.Entry<MethodDef, ADDef> entry : methods.entrySet()) {
      MethodDef defined = entry.getKey();
      if (defined.isConstructor()) {
        analyzer.error(
            "Constructor %s for %s.%s found; only interfaces and annotations allowed for OCDs",
            defined.getName(), clazz.getClassName().getFQN(), defined.getName());
      }
      if (defined.getPrototype().length > 0) {
        analyzer.error(
            "Element %s for %s.%s has parameters; only no-parameter elements in an OCD interface allowed",
            defined.getName(), clazz.getClassName().getFQN(), defined.getName());
        continue;
      }
      ADDef ad = entry.getValue();
      ocd.attributes.add(ad);
      ad.id = fixup(defined.getName());
      ad.name = space(defined.getName());
      String rtype = defined.getGenericReturnType();
      if (rtype.endsWith("[]")) {
        ad.cardinality = Integer.MAX_VALUE;
        rtype = rtype.substring(0, rtype.length() - 2);
      }
      Matcher m = GENERIC.matcher(rtype);
      if (m.matches()) {
        boolean knownCollection = m.group(2) != null;
        boolean collection = knownCollection || identifiableCollection(m.group(3), false, true);
        if (collection) {
          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());
          rtype = Clazz.objectDescriptorToFQN(m.group(4));
          ad.cardinality = Integer.MIN_VALUE;
        }
      }
      if (rtype.indexOf('<') > 0) {
        rtype = rtype.substring(0, rtype.indexOf('<'));
      }
      ad.type = getType(rtype);

      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 (ad.ad != null) {
        doAD(ad);
      }
      if (ad.defaults == null && clazz.isAnnotation() && defined.getConstant() != null) {
        // defaults from annotation default
        Object value = defined.getConstant();
        boolean isClass = false;
        TypeRef type = defined.getType().getClassRef();
        if (!type.isPrimitive()) {
          if (Class.class.getName().equals(type.getFQN())) {
            isClass = true;
          } else {
            try {
              Clazz r = analyzer.findClass(type);
              if (r.isAnnotation()) {
                analyzer.warning(
                    "Nested annotation type found in field % s, %s",
                    defined.getName(), type.getFQN());
                return;
              }
            } catch (Exception e) {
              analyzer.error(
                  "Exception looking at annotation type default for element with descriptor %s,  type %s",
                  e, defined, type);
            }
          }
        }
        if (value != null) {
          if (value.getClass().isArray()) {
            // add element individually
            ad.defaults = new String[Array.getLength(value)];
            for (int i = 0; i < Array.getLength(value); i++) {
              Object element = Array.get(value, i);
              ad.defaults[i] = valueToProperty(element, isClass);
            }
          } else {
            ad.defaults = new String[] {valueToProperty(value, isClass)};
          }
        }
      }
    }
  }
Example #24
0
  public static void testPrecedence() throws Exception {
    File base = IO.getFile("src/test");
    String a = "a=a.props\n";
    String b = "a=b.props\n";
    File aa = new File(base, "a.props");
    File bb = new File(base, "b.props");
    write(aa, a);
    write(bb, b);

    Analyzer analyzer = new Analyzer();
    analyzer.setBase(base);
    Properties x = new Properties();
    x.put("a", "x");
    x.put("-include", "a.props, b.props");
    analyzer.setProperties(x);
    assertEquals("b.props", analyzer.getProperty("a")); // from org

    analyzer = new Analyzer();
    analyzer.setBase(base);
    x = new Properties();
    x.put("a", "x");
    x.put("-include", "~a.props, b.props");
    analyzer.setProperties(x);
    assertEquals("b.props", analyzer.getProperty("a")); // from org

    analyzer = new Analyzer();
    analyzer.setBase(base);
    x = new Properties();
    x.put("a", "x");
    x.put("-include", "a.props, ~b.props");
    analyzer.setProperties(x);
    assertEquals("a.props", analyzer.getProperty("a")); // from org

    analyzer = new Analyzer();
    analyzer.setBase(base);
    x = new Properties();
    x.put("a", "x");
    x.put("-include", "~a.props, ~b.props");
    analyzer.setProperties(x);
    assertEquals("x", analyzer.getProperty("a")); // from org

    aa.delete();
    bb.delete();
  }