use of aQute.bnd.osgi.Instructions in project bnd by bndtools.
the class ProjectLauncherImpl method executable.
/**
* Create a standalone executable. All entries on the runpath are rolled out
* into the JAR and the runbundles are copied to a directory in the jar. The
* launcher will see that it starts in embedded mode and will automatically
* detect that it should load the bundles from inside. This is drive by the
* launcher.embedded flag.
*
* @throws Exception
*/
@Override
public Jar executable() throws Exception {
// TODO use constants in the future
Parameters packageHeader = OSGiHeader.parseHeader(getProject().getProperty("-package"));
boolean useShas = packageHeader.containsKey("jpm");
logger.debug("useShas {} {}", useShas, packageHeader);
Jar jar = new Jar(getProject().getName());
Builder b = new Builder();
getProject().addClose(b);
if (!getProject().getIncludeResource().isEmpty()) {
b.setIncludeResource(getProject().getIncludeResource().toString());
b.setProperty(Constants.RESOURCEONLY, "true");
b.build();
if (b.isOk()) {
jar.addAll(b.getJar());
}
getProject().getInfo(b);
}
List<String> runpath = getRunpath();
Set<String> runpathShas = new LinkedHashSet<String>();
Set<String> runbundleShas = new LinkedHashSet<String>();
List<String> classpath = new ArrayList<String>();
for (String path : runpath) {
logger.debug("embedding runpath {}", path);
File file = new File(path);
if (file.isFile()) {
if (useShas) {
String sha = SHA1.digest(file).asHex();
runpathShas.add(sha + ";name=\"" + file.getName() + "\"");
} else {
String newPath = nonCollidingPath(file, jar);
jar.putResource(newPath, new FileResource(file));
classpath.add(newPath);
}
}
}
// Copy the bundles to the JAR
List<String> runbundles = (List<String>) getRunBundles();
List<String> actualPaths = new ArrayList<String>();
for (String path : runbundles) {
logger.debug("embedding run bundles {}", path);
File file = new File(path);
if (!file.isFile())
getProject().error("Invalid entry in -runbundles %s", file);
else {
if (useShas) {
String sha = SHA1.digest(file).asHex();
runbundleShas.add(sha + ";name=\"" + file.getName() + "\"");
actualPaths.add("${JPMREPO}/" + sha);
} else {
String newPath = nonCollidingPath(file, jar);
jar.putResource(newPath, new FileResource(file));
actualPaths.add(newPath);
}
}
}
LauncherConstants lc = getConstants(actualPaths, true);
lc.embedded = !useShas;
// cannot use local info
lc.storageDir = null;
final Properties p = lc.getProperties(new UTF8Properties());
ByteArrayOutputStream bout = new ByteArrayOutputStream();
p.store(bout, "");
jar.putResource(LauncherConstants.DEFAULT_LAUNCHER_PROPERTIES, new EmbeddedResource(bout.toByteArray(), 0L));
Manifest m = new Manifest();
Attributes main = m.getMainAttributes();
for (Entry<Object, Object> e : getProject().getFlattenedProperties().entrySet()) {
String key = (String) e.getKey();
if (key.length() > 0 && Character.isUpperCase(key.charAt(0)))
main.putValue(key, (String) e.getValue());
}
Instructions instructions = new Instructions(getProject().getProperty(Constants.REMOVEHEADERS));
Collection<Object> result = instructions.select(main.keySet(), false);
main.keySet().removeAll(result);
if (useShas) {
logger.debug("Use JPM launcher");
m.getMainAttributes().putValue("Main-Class", JPM_LAUNCHER_FQN);
m.getMainAttributes().putValue("JPM-Classpath", Processor.join(runpathShas));
m.getMainAttributes().putValue("JPM-Runbundles", Processor.join(runbundleShas));
URLResource jpmLauncher = new URLResource(this.getClass().getResource("/" + JPM_LAUNCHER));
jar.putResource(JPM_LAUNCHER, jpmLauncher);
doStart(jar, JPM_LAUNCHER_FQN);
} else {
logger.debug("Use Embedded launcher");
m.getMainAttributes().putValue("Main-Class", EMBEDDED_LAUNCHER_FQN);
m.getMainAttributes().putValue(EmbeddedLauncher.EMBEDDED_RUNPATH, Processor.join(classpath));
URLResource embeddedLauncher = new URLResource(this.getClass().getResource("/" + EMBEDDED_LAUNCHER));
jar.putResource(EMBEDDED_LAUNCHER, embeddedLauncher);
doStart(jar, EMBEDDED_LAUNCHER_FQN);
}
if (getProject().getProperty(Constants.DIGESTS) != null)
jar.setDigestAlgorithms(getProject().getProperty(Constants.DIGESTS).trim().split("\\s*,\\s*"));
else
jar.setDigestAlgorithms(new String[] { "SHA-1", "MD-5" });
jar.setManifest(m);
cleanup();
return jar;
}
use of aQute.bnd.osgi.Instructions in project bnd by bndtools.
the class MetatypeAnnotations method analyzeJar.
public boolean analyzeJar(Analyzer analyzer) throws Exception {
this.minVersion = MetatypeVersion.VERSION_1_2;
Parameters header = OSGiHeader.parseHeader(analyzer.getProperty(Constants.METATYPE_ANNOTATIONS, "*"));
if (header.size() == 0)
return false;
Parameters optionsHeader = OSGiHeader.parseHeader(analyzer.getProperty(Constants.METATYPE_ANNOTATIONS_OPTIONS));
EnumSet<Options> options = EnumSet.noneOf(Options.class);
for (Map.Entry<String, Attrs> entry : optionsHeader.entrySet()) {
try {
Options.parseOption(entry, options, this);
} catch (IllegalArgumentException e) {
analyzer.error("Unrecognized %s value %s with attributes %s, expected values are %s", Constants.METATYPE_ANNOTATIONS_OPTIONS, entry.getKey(), entry.getValue(), EnumSet.allOf(Options.class));
}
}
Map<TypeRef, OCDDef> classToOCDMap = new HashMap<TypeRef, OCDDef>();
Set<String> ocdIds = new HashSet<String>();
Set<String> pids = new HashSet<String>();
Instructions instructions = new Instructions(header);
XMLAttributeFinder finder = new XMLAttributeFinder(analyzer);
List<Clazz> list = Create.list();
for (Clazz c : analyzer.getClassspace().values()) {
for (Instruction instruction : instructions.keySet()) {
if (instruction.matches(c.getFQN())) {
if (!instruction.isNegated()) {
list.add(c);
OCDDef definition = OCDReader.getOCDDef(c, analyzer, options, finder, minVersion);
if (definition != null) {
classToOCDMap.put(c.getClassName(), definition);
}
}
break;
}
}
}
// process Designate annotations after OCD annotations
for (Clazz c : list) {
DesignateReader.getDesignate(c, analyzer, classToOCDMap, finder);
}
for (Map.Entry<TypeRef, OCDDef> entry : classToOCDMap.entrySet()) {
TypeRef c = entry.getKey();
OCDDef definition = entry.getValue();
definition.prepare(analyzer);
if (!ocdIds.add(definition.id)) {
analyzer.error("Duplicate OCD id %s from class %s; known ids %s", definition.id, c.getFQN(), ocdIds);
}
for (DesignateDef dDef : definition.designates) {
if (dDef.pid != null && !pids.add(dDef.pid)) {
analyzer.error("Duplicate pid %s from class %s", dDef.pid, c.getFQN());
}
}
String name = "OSGI-INF/metatype/" + analyzer.validResourcePath(definition.id, "Invalid resource name") + ".xml";
analyzer.getJar().putResource(name, new TagResource(definition.getTag()));
}
return false;
}
use of aQute.bnd.osgi.Instructions in project bnd by bndtools.
the class Main method _command.
@Description("Manage the jpm4j commands")
public void _command(CommandOptions opts) throws Exception {
if (opts.remove()) {
Instructions instrs = new Instructions(opts._arguments());
for (CommandData cmd : jpm.getCommands()) {
if (instrs.matches(cmd.name)) {
jpm.deleteCommand(cmd.name);
}
}
return;
}
if (opts._arguments().isEmpty()) {
print(jpm.getCommands());
return;
}
String cmd = opts._arguments().get(0);
CommandData data = jpm.getCommand(cmd);
if (data == null) {
error("Not found: %s", cmd);
} else {
CommandData newer = new CommandData();
JustAnotherPackageManager.xcopy(data, newer);
if (updateCommandData(newer, opts)) {
jpm.deleteCommand(data.name);
String result = jpm.createCommand(newer, true);
if (result != null)
error("Failed to update command %s: %s", cmd, result);
}
print(newer);
}
}
use of aQute.bnd.osgi.Instructions in project bnd by bndtools.
the class Windows method _path.
@Description("Add the bin directory for this jpm to your PATH in the user's environment variables")
public void _path(PathOptions options) {
RegistryKey env = RegistryKey.HKEY_CURRENT_USER.getSubKey("Environment");
if (env == null) {
reporter.error("Cannot find key for environment HKEY_CURRENT_USER/Environment");
return;
}
String path = env.getString("Path");
String[] parts = path == null ? new String[0] : path.split(File.pathSeparator);
List<String> paths = new ArrayList<String>(Arrays.asList(parts));
boolean save = false;
if (options.extra() != null) {
paths.addAll(options.extra());
save = true;
}
for (int i = 0; i < parts.length; i++) {
System.out.printf("%2d:%s %s %s%n", i, parts[i].toLowerCase().contains("jpm") ? "*" : " ", new File(parts[i]).isDirectory() ? " " : "!", parts[i]);
}
if (options.remove()) {
if (!paths.remove(jpm.getBinDir().getAbsolutePath())) {
reporter.error("Could not find %s", jpm.getBinDir());
}
save = true;
}
if (options.delete() != null) {
Instructions instr = new Instructions(options.delete());
paths = new ArrayList<String>(instr.select(paths, true));
}
if (options.add()) {
paths.remove(jpm.getBinDir().getAbsolutePath());
paths.add(jpm.getBinDir().getAbsolutePath());
save = true;
}
if (save) {
String p = Strings.join(File.pathSeparator, paths);
env.setString("Path", p);
}
}
use of aQute.bnd.osgi.Instructions in project bnd by bndtools.
the class JavaElement method classElement.
/**
* Calculate the class element. This requires parsing the class file and
* finding all the methods that were added etc. The parsing will take super
* interfaces and super classes into account. For this reason it maintains a
* queue of classes/interfaces to parse.
*
* @param analyzer
* @param clazz
* @param infos
* @throws Exception
*/
Element classElement(final Clazz clazz) throws Exception {
Element e = cache.get(clazz);
if (e != null)
return e;
final Set<Element> members = Create.set();
final Set<MethodDef> methods = Create.set();
final Set<Clazz.FieldDef> fields = Create.set();
final MultiMap<Clazz.Def, Element> annotations = new MultiMap<Clazz.Def, Element>();
final TypeRef name = clazz.getClassName();
final String fqn = name.getFQN();
final String shortName = name.getShortName();
// Check if this clazz is actually a provider or not
// providers must be listed in the exported package in the
// PROVIDER_TYPE directive.
Instructions matchers = providerMatcher.get(name.getPackageRef());
boolean p = matchers != null && matchers.matches(shortName);
final AtomicBoolean provider = new AtomicBoolean(p);
//
// Check if we already had this clazz in the cache
//
// for super classes
Element before = cache.get(clazz);
if (before != null)
return before;
clazz.parseClassFileWithCollector(new ClassDataCollector() {
boolean memberEnd;
Clazz.FieldDef last;
@Override
public void version(int minor, int major) {
javas.add(Clazz.JAVA.getJava(major, minor));
}
@Override
public void method(MethodDef defined) {
if ((defined.isProtected() || defined.isPublic())) {
last = defined;
methods.add(defined);
} else {
last = null;
}
}
@Override
public void deprecated() {
if (memberEnd)
clazz.setDeprecated(true);
else if (last != null)
last.setDeprecated(true);
}
@Override
public void field(Clazz.FieldDef defined) {
if (defined.isProtected() || defined.isPublic()) {
last = defined;
fields.add(defined);
} else
last = null;
}
@Override
public void constant(Object o) {
if (last != null) {
// Must be accessible now
last.setConstant(o);
}
}
@Override
public void extendsClass(TypeRef name) throws Exception {
String comment = null;
if (!clazz.isInterface())
comment = inherit(members, name);
Clazz c = analyzer.findClass(name);
if ((c == null || c.isPublic()) && !name.isObject())
members.add(new Element(EXTENDS, name.getFQN(), null, MICRO, MAJOR, comment));
}
@Override
public void implementsInterfaces(TypeRef[] names) throws Exception {
// ignore type reordering
Arrays.sort(names);
for (TypeRef name : names) {
String comment = null;
if (clazz.isInterface() || clazz.isAbstract())
comment = inherit(members, name);
members.add(new Element(IMPLEMENTS, name.getFQN(), null, MINOR, MAJOR, comment));
}
}
/**
*/
Set<Element> OBJECT = Create.set();
public String inherit(final Set<Element> members, TypeRef name) throws Exception {
if (name.isObject()) {
if (OBJECT.isEmpty()) {
Clazz c = analyzer.findClass(name);
if (c == null) {
// available
return null;
}
Element s = classElement(c);
for (Element child : s.children) {
if (INHERITED.contains(child.type)) {
String n = child.getName();
if (child.type == METHOD) {
if (n.startsWith("<init>") || "getClass()".equals(child.getName()) || n.startsWith("wait(") || n.startsWith("notify(") || n.startsWith("notifyAll("))
continue;
}
if (isStatic(child))
continue;
OBJECT.add(child);
}
}
}
members.addAll(OBJECT);
} else {
Clazz c = analyzer.findClass(name);
if (c == null) {
return inherit(members, analyzer.getTypeRef("java/lang/Object"));
}
Element s = classElement(c);
for (Element child : s.children) {
if (isStatic(child))
continue;
if (INHERITED.contains(child.type) && !child.name.startsWith("<")) {
members.add(child);
}
}
}
return null;
}
private boolean isStatic(Element child) {
boolean isStatic = child.get("static") != null;
return isStatic;
}
/**
* Deprecated annotations and Provider/Consumer Type (both bnd and
* OSGi) are treated special. Other annotations are turned into a
* tree. Starting with ANNOTATED, and then properties. A property is
* a PROPERTY property or an ANNOTATED property if it is an
* annotation. If it is an array, the key is suffixed with the
* index.
*
* <pre>
* public @interface Outer { Inner[] value(); }
* public @interface Inner { String[] value(); } @Outer(
* { @Inner("1","2"}) } class Xyz {} ANNOTATED Outer
* (CHANGED/CHANGED) ANNOTATED Inner (CHANGED/CHANGED) PROPERTY
* value.0=1 (CHANGED/CHANGED) PROPERTY value.1=2 (CHANGED/CHANGED)
* </pre>
*/
@Override
public void annotation(Annotation annotation) {
if (Deprecated.class.getName().equals(annotation.getName().getFQN())) {
if (memberEnd)
clazz.setDeprecated(true);
else if (last != null)
last.setDeprecated(true);
return;
}
Element e = annotatedToElement(annotation);
if (memberEnd) {
members.add(e);
//
// Check for the provider/consumer. We use strings because
// these are not officially
// released yet
//
String name = annotation.getName().getFQN();
if ("aQute.bnd.annotation.ProviderType".equals(name) || "org.osgi.annotation.versioning.ProviderType".equals(name)) {
provider.set(true);
} else if ("aQute.bnd.annotation.ConsumerType".equals(name) || "org.osgi.annotation.versioning.ConsumerType".equals(name)) {
provider.set(false);
}
} else if (last != null)
annotations.add(last, e);
}
/*
* Return an ANNOTATED element for this annotation. An ANNOTATED
* element contains either PROPERTY children or ANNOTATED children.
*/
private Element annotatedToElement(Annotation annotation) {
Collection<Element> properties = Create.set();
for (String key : annotation.keySet()) {
addAnnotationMember(properties, key, annotation.get(key));
}
return new Element(ANNOTATED, annotation.getName().getFQN(), properties, CHANGED, CHANGED, null);
}
/*
* This method detects 3 cases: An Annotation, which means it
* creates a new child ANNOTATED element, an array, which means it
* will repeat recursively but suffixes the key with the index, or a
* simple value which is turned into a string.
*/
private void addAnnotationMember(Collection<Element> properties, String key, Object member) {
if (member instanceof Annotation) {
properties.add(annotatedToElement((Annotation) member));
} else if (member.getClass().isArray()) {
int l = Array.getLength(member);
for (int i = 0; i < l; i++) {
addAnnotationMember(properties, key + "." + i, Array.get(member, i));
}
} else {
StringBuilder sb = new StringBuilder();
sb.append(key);
sb.append('=');
if (member instanceof String) {
sb.append("'");
sb.append(member);
sb.append("'");
} else
sb.append(member);
properties.add(new Element(PROPERTY, sb.toString(), null, CHANGED, CHANGED, null));
}
}
@Override
public void innerClass(TypeRef innerClass, TypeRef outerClass, String innerName, int innerClassAccessFlags) throws Exception {
Clazz clazz = analyzer.findClass(innerClass);
if (clazz != null)
clazz.setInnerAccess(innerClassAccessFlags);
if (Modifier.isProtected(innerClassAccessFlags) || Modifier.isPublic(innerClassAccessFlags))
return;
notAccessible.add(innerClass);
}
@Override
public void memberEnd() {
memberEnd = true;
}
});
// This is the heart of the semantic versioning. If we
// add or remove a method from an interface then
Delta add;
Delta remove;
Type type;
if (clazz.isInterface())
if (clazz.isAnnotation())
type = ANNOTATION;
else
type = INTERFACE;
else if (clazz.isEnum())
type = ENUM;
else
type = CLASS;
if (type == INTERFACE) {
if (provider.get()) {
// Adding a method for a provider is not an issue
// because it must be aware of the changes
add = MINOR;
// Removing a method influences consumers since they
// tend to call this guy.
remove = MAJOR;
} else {
// Adding a method is a major change
// because the consumer has to implement it
// or the provider will call a non existent
// method on the consumer
add = MAJOR;
// Removing a method is not an issue for
// providers, however, consumers could potentially
// call through this interface :-(
remove = MAJOR;
}
} else {
// Adding a method to a class can never do any harm
// except when the class is extended and the new
// method clashes with the new method. That is
// why API classes in general should be final, at
// least not extended by consumers.
add = MINOR;
// Removing it will likely hurt consumers
remove = MAJOR;
}
for (MethodDef m : methods) {
if (m.isSynthetic()) {
// Ignore synthetic methods
continue;
}
Collection<Element> children = annotations.get(m);
if (children == null)
children = new HashSet<Element>();
access(children, m.getAccess(), m.isDeprecated(), provider.get());
// in a final class.
if (clazz.isFinal())
children.remove(FINAL);
children.add(getReturn(m.getType()));
if (clazz.isInterface() && !m.isAbstract()) {
//
// We have a Java 8 default method!
// Such a method is always a minor update
//
add = MINOR;
}
String signature = m.getName() + toString(m.getPrototype());
Element member = new Element(METHOD, signature, children, add, provider.get() && !m.isPublic() ? MINOR : remove, null);
if (!members.add(member)) {
members.remove(member);
members.add(member);
}
}
for (Clazz.FieldDef f : fields) {
if (f.isSynthetic()) {
// Ignore synthetic fields
continue;
}
Collection<Element> children = annotations.get(f);
if (children == null)
children = new HashSet<Element>();
// Fields can have a constant value, this is a new element
if (f.getConstant() != null) {
children.add(new Element(CONSTANT, f.getConstant().toString(), null, CHANGED, CHANGED, null));
}
access(children, f.getAccess(), f.isDeprecated(), provider.get());
children.add(getReturn(f.getType()));
Element member = new Element(FIELD, f.getName(), children, MINOR, provider.get() && !f.isPublic() ? MINOR : MAJOR, null);
if (!members.add(member)) {
members.remove(member);
members.add(member);
}
}
access(members, clazz.getAccess(), clazz.isDeprecated(), provider.get());
// And make the result
Element s = new Element(type, fqn, members, MINOR, MAJOR, null);
cache.put(clazz, s);
return s;
}
Aggregations