blob: 8dbca34fa3e327e7ef980f7fcdfcaa306fc36a8c [file] [log] [blame]
Richard S. Hall85bafab2009-07-13 13:25:46 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20package org.cauldron.bld.ivy;
21
22import java.io.File;
23import java.io.IOException;
24import java.net.URI;
25import java.text.ParseException;
26import java.util.ArrayList;
27import java.util.Collection;
28import java.util.List;
29
30import org.apache.ivy.core.module.descriptor.ModuleDescriptor;
31import org.apache.ivy.core.module.id.ModuleRevisionId;
32import org.cauldron.bld.config.BldFactory;
33import org.cauldron.bld.config.IBldProject;
34import org.cauldron.bld.config.IBldProject.IBldBundle;
35import org.cauldron.bld.core.internal.model.eclipse.SigilBundle;
36import org.cauldron.bld.core.internal.model.osgi.BundleModelElement;
37import org.cauldron.bld.core.licence.ILicensePolicy;
38import org.cauldron.sigil.model.common.VersionRange;
39import org.cauldron.sigil.model.eclipse.ISigilBundle;
40import org.cauldron.sigil.model.osgi.IBundleModelElement;
41import org.cauldron.sigil.model.osgi.IPackageExport;
42import org.cauldron.sigil.model.osgi.IPackageImport;
43import org.cauldron.sigil.model.osgi.IRequiredBundle;
44import org.cauldron.sigil.repository.AbstractBundleRepository;
45import org.cauldron.sigil.repository.IRepositoryVisitor;
46
47import org.osgi.framework.Version;
48
49public class ProjectRepository extends AbstractBundleRepository {
50 private ArrayList<ISigilBundle> bundles;
51 private ArrayList<ISigilBundle> wildBundles;
52 private String projectFilePattern;
53
54 /* package */ProjectRepository(String id, String projectFilePattern) {
55 super(id);
56 this.projectFilePattern = projectFilePattern.replaceAll("\\[sigilproject\\]",
57 IBldProject.PROJECT_FILE);
58 }
59
60 @Override
61 public void accept(IRepositoryVisitor visitor, int options) {
62 for (ISigilBundle b : getBundles()) {
63 if (!visitor.visit(b)) {
64 break;
65 }
66 }
67 }
68
69 // override to provide fuzzy matching for wild-card exports.
70 @Override
71 public Collection<ISigilBundle> findAllProviders(final IPackageImport pi, int options) {
72 return findProviders(pi, options, false);
73 }
74
75 @Override
76 public ISigilBundle findProvider(IPackageImport pi, int options) {
77 Collection<ISigilBundle> found = findProviders(pi, options, true);
78 return found.isEmpty() ? null : found.iterator().next();
79 }
80
81 private Collection<ISigilBundle> findProviders(final IPackageImport pi, int options,
82 boolean findFirst) {
83 ArrayList<ISigilBundle> found = new ArrayList<ISigilBundle>();
84 ILicensePolicy policy = findPolicy(pi);
85 String name = pi.getPackageName();
86 VersionRange versions = pi.getVersions();
87
88 // find exact match(es)
89 for (ISigilBundle bundle : getBundles()) {
90 if (policy.accept(bundle)) {
91 for (IPackageExport exp : bundle.getBundleInfo().getExports()) {
92 if (name.equals(exp.getPackageName())
93 && versions.contains(exp.getVersion())) {
94 found.add(bundle);
95 if (findFirst)
96 return found;
97 }
98 }
99 }
100 }
101
102 if (!found.isEmpty())
103 return found;
104
105 // find best fuzzy match
106 ISigilBundle fuzzyMatch = null;
107 int fuzzyLen = 0;
108
109 for (ISigilBundle bundle : getWildBundles()) {
110 if (policy.accept(bundle)) {
111 for (IPackageExport exp : bundle.getBundleInfo().getExports()) {
112 String export = exp.getPackageName();
113 if (export.endsWith("*")) {
114 String export1 = export.substring(0, export.length() - 1);
115 if ((name.startsWith(export1) || export1.equals(name + "."))
116 && versions.contains(exp.getVersion())) {
117 if (export1.length() > fuzzyLen) {
118 fuzzyLen = export1.length();
119 fuzzyMatch = bundle;
120 }
121 }
122 }
123 }
124 }
125 }
126
127 if (fuzzyMatch != null)
128 found.add(fuzzyMatch);
129
130 return found;
131 }
132
133 private synchronized void init() {
134 System.out.println("Sigil: loading Project Repository: " + projectFilePattern);
135
136 ArrayList<File> projects = new ArrayList<File>();
137
138 for (String pattern : projectFilePattern.split("\\s+")) {
139 try {
140 Collection<File> files = FindUtil.findFiles(pattern);
141 if (files.isEmpty()) {
142 Log.warn("ProjectRepository: no projects match: " + pattern);
143 } else {
144 projects.addAll(files);
145 }
146 } catch (IOException e) {
147 // pattern root dir does not exist
148 Log.error("ProjectRepository: " + pattern + ": " + e.getMessage());
149 }
150 }
151
152 if (projects.isEmpty()) {
153 throw new IllegalArgumentException(
154 "ProjectRepository: no projects found using pattern: "
155 + projectFilePattern);
156 }
157
158 bundles = new ArrayList<ISigilBundle>();
159
160 for (File proj : projects) {
161 try {
162 addBundles(proj, bundles);
163 } catch (IOException e) {
164 Log.warn("Skipping project: " + proj + ": " + e.getMessage());
165 } catch (ParseException e) {
166 Log.warn("Skipping project: " + proj + ": " + e.getMessage());
167 }
168 }
169 }
170
171 private List<ISigilBundle> getBundles() {
172 if (bundles == null) {
173 init();
174 }
175 return bundles;
176 }
177
178 private List<ISigilBundle> getWildBundles() {
179 if (wildBundles == null) {
180 wildBundles = new ArrayList<ISigilBundle>();
181 for (ISigilBundle bundle : getBundles()) {
182 for (IPackageExport exp : bundle.getBundleInfo().getExports()) {
183 String export = exp.getPackageName();
184 if (export.endsWith("*")) {
185 wildBundles.add(bundle);
186 break;
187 }
188 }
189 }
190 }
191 return wildBundles;
192 }
193
194 public void refresh() {
195 bundles = null;
196 wildBundles = null;
197 notifyChange();
198 }
199
200 private void addBundles(File file, List<ISigilBundle> list) throws IOException,
201 ParseException {
202 URI uri = file.getCanonicalFile().toURI();
203 IBldProject project = BldFactory.getProject(uri);
204
205 for (IBldBundle bb : project.getBundles()) {
206 IBundleModelElement info = new BundleModelElement();
207
208 for (IPackageExport pexport : bb.getExports()) {
209 info.addExport(pexport);
210 }
211
212 for (IPackageImport import1 : bb.getImports()) {
213 IPackageImport clone = (IPackageImport) import1.clone();
214 clone.setParent(null);
215 info.addImport(clone);
216 }
217
218 for (IRequiredBundle require : bb.getRequires()) {
219 IRequiredBundle clone = (IRequiredBundle) require.clone();
220 clone.setParent(null);
221 info.addRequiredBundle(clone);
222 }
223
224 info.setSymbolicName(bb.getSymbolicName());
225
226 Version version = new Version(bb.getVersion());
227 info.setVersion(version);
228
229 ProjectBundle pb = new ProjectBundle();
230 pb.setBundleInfo(info);
231 pb.setId(bb.getId());
232
233 ModuleDescriptor md = SigilParser.instance().parseDescriptor(uri.toURL());
234
235 ModuleRevisionId mrid = md.getModuleRevisionId();
236 pb.setModule(mrid.getName());
237 pb.setOrg(mrid.getOrganisation());
238 // XXX: should revision be configurable?
239 pb.setRevision("latest." + md.getStatus());
240
241 list.add(pb);
242 Log.debug("ProjectRepository: added " + pb);
243 Log.debug("ProjectRepository: exports " + bb.getExports());
244 }
245 }
246
247 public static class ProjectBundle extends SigilBundle {
248 private String id;
249 private String module;
250 private String org;
251 private String revision;
252
253 @Override
254 public String toString() {
255 return "ProjectBundle[" + org + "@" + module + (id == null ? "" : "$" + id)
256 + "#" + revision + "]";
257 }
258
259 public String getModule() {
260 return module;
261 }
262
263 public void setModule(String module) {
264 this.module = module;
265 }
266
267 public String getId() {
268 return id;
269 }
270
271 public void setId(String id) {
272 this.id = id;
273 }
274
275 public String getRevision() {
276 return revision;
277 }
278
279 public void setRevision(String rev) {
280 this.revision = rev;
281 }
282
283 public String getOrg() {
284 return org;
285 }
286
287 public void setOrg(String org) {
288 this.org = org;
289 }
290 }
291
292}