blob: 4457f16fef4ac228ed97bae67a28040599480993 [file] [log] [blame]
Stuart McCulloch26e7a5a2011-10-17 10:31:43 +00001package aQute.bnd.resolver;
2
3import java.io.*;
4import java.util.*;
5import java.util.jar.*;
6
7import aQute.bnd.build.*;
8import aQute.bnd.resolver.Resource.Requirement;
9import aQute.lib.collections.*;
10import aQute.lib.osgi.*;
11import aQute.libg.generics.*;
12
13public class Resolver extends Processor {
14
15 final Set<Resource> resources = new HashSet<Resource>();
16 private Map<Resource.Requirement, Set<Resource>> cache = new IdentityHashMap<Resource.Requirement, Set<Resource>>();
17
18 public void add(Container c) throws Exception {
19 List<File> files = new ArrayList<File>();
20 c.contributeFiles(files, this);
21 for (File f : files) {
22 add(f);
23 }
24 }
25
26 public void addAll(Collection<Container> containers) throws Exception {
27 for (Container c : containers) {
28 add(c);
29 }
30 }
31
32 public Resolution resolve() throws Exception {
33 // Split fragments and bundles
34 Set<Resource> active = new HashSet<Resource>();
35 Set<Resource> fragments = new HashSet<Resource>();
36 Set<Resource> singletons = new HashSet<Resource>();
37
38 for (Resource r : resources) {
39 if (r.fragments != null) {
40 active.add(r);
41 if (r.singleton)
42 singletons.add(r);
43 } else
44 fragments.add(r);
45 }
46
47 // Attach fragments
48 for (Resource r : fragments) {
49 Collection<Resource> hosts = find(active, r.requirements, new HashSet<Resource>());
50 for (Resource host : hosts) {
51 host.fragments.add(host);
52 }
53 }
54
55 // Create a list of all the requirements
56 Set<Resource.Requirement> reqs = new HashSet<Resource.Requirement>();
57 for (Resource r : active) {
58 reqs.addAll(r.requirements);
59 // And its attached fragments
60 for (Resource f : r.fragments) {
61 reqs.addAll(f.requirements);
62 }
63 }
64
65 Set<Resource.Requirement> optional = Create.set();
66 Set<Resource.Requirement> unresolved = Create.set();
67 Map<Resource.Requirement, Resource> unique = Create.map();
68 MultiMap<Requirement, Resource> multiple = new MultiMap<Requirement, Resource>();
69
70 for (Resource.Requirement req : reqs) {
71 Collection<Resource> solutions = find(active, req, new HashSet<Resource>());
72 if (solutions.isEmpty()) {
73 if (req.optional)
74 optional.add(req);
75 else
76 unresolved.add(req);
77 } else if (solutions.size() == 1)
78 unique.put(req, solutions.iterator().next());
79 else {
80 multiple.addAll(req, solutions);
81 }
82 }
83
84 // If we have unresolveds, tough shit
85
86 if (!unresolved.isEmpty()) {
87 for (Requirement r : unresolved) {
88 error("Unresolved %s", r);
89 }
90 }
91
92 // Calculate our singleton candidates
93 MultiMap<String, Resource> picked = new MultiMap<String, Resource>();
94 for (Resource r : singletons) {
95 picked.add(r.bsn, r);
96 }
97
98 // Remove any singletons that are alone
99 // and verify that if there are multiple they are not
100 // both in the unique solutions
101 for (Iterator<Map.Entry<String, Set<Resource>>> i = picked.entrySet().iterator(); i
102 .hasNext();) {
103 Map.Entry<String, Set<Resource>> entry = i.next();
104 if (entry.getValue().size() == 1)
105 i.remove();
106 else {
107 Set<Resource> x = new HashSet<Resource>(entry.getValue());
108 boolean changed = x.retainAll(unique.values());
109 if (x.size() > 1) {
110 // We need multiple singleton bundles with the same bsn
111 error("Singleton conflict: %s", x);
112 } else if (changed) {
113 Set<Resource> delta = new HashSet<Resource>(entry.getValue());
114 delta.removeAll(x);
115
116 // We've removed bundles from the possible solutions
117 for (Iterator<Resource> it = multiple.all(); i.hasNext();) {
118 Resource r = it.next();
119 if (delta.contains(r)) {
120 it.remove();
121 }
122 }
123 }
124 }
125 }
126
127 Resolution res = new Resolution();
128 res.multiple = multiple;
129 res.unique = unique;
130 res.unresolved = unresolved;
131 return res;
132 }
133
134 private Collection<Resource> find(Set<Resource> active, Set<Resource.Requirement> requirements,
135 Set<Resource> result) {
136 for (Resource.Requirement req : requirements) {
137 Set<Resource> resources = cache.get(req);
138 if (resources != null) {
139 result.addAll(resources);
140 } else {
141 resources = find(active, req, new HashSet<Resource>());
142 cache.put(req, resources);
143 result.addAll(resources);
144 }
145 }
146 return result;
147 }
148
149 private Set<Resource> find(Set<Resource> active, Requirement req, Set<Resource> result) {
150 for (Resource r : active) {
151 for (Resource.Capability cap : r.capabilities) {
152 if ( cap.name.equals(req.name))
153 System.out.println("Yes");
154 if (req.matches(cap))
155 result.add(r);
156 }
157 }
158 return result;
159 }
160
161 public void add(File file) throws IOException {
162 JarFile jf = new JarFile(file);
163 try {
164 Manifest m = jf.getManifest();
165 Resource r = new Resource(this, m);
166 resources.add(r);
167 } finally {
168 jf.close();
169 }
170 }
171
172}