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; }
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()); } } } } }
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); }
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()); }
/** 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")); }
/** 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")); }
/** * 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); } }
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")); }
/** * 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); }
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; } }
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)); }
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()); }
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; }
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; }
@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); } }
@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); } }
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(); } }
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")); }
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)}; } } } } }
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(); }