blob: 72715b03640785723b0fc3e6059d6d47e63024d1 [file] [log] [blame]
Stuart McCulloch26e7a5a2011-10-17 10:31:43 +00001package aQute.bnd.build;
2
3import java.io.*;
4import java.util.*;
5import java.util.jar.*;
6
7import aQute.bnd.service.RepositoryPlugin.Strategy;
8import aQute.lib.osgi.*;
9
10public class Container {
11 public enum TYPE {
12 REPO, PROJECT, EXTERNAL, LIBRARY, ERROR
13 }
14
15 final File file;
16 final TYPE type;
17 final String bsn;
18 final String version;
19 final String error;
20 final Project project;
21 volatile Map<String, String> attributes;
22 private long manifestTime;
23 private Manifest manifest;
24
25 Container(Project project, String bsn, String version, TYPE type, File source, String error,
26 Map<String, String> attributes) {
27 this.bsn = bsn;
28 this.version = version;
29 this.type = type;
30 this.file = source != null ? source : new File("/" + bsn + ":" + version + ":" + type);
31 this.project = project;
32 this.error = error;
33 if (attributes == null || attributes.isEmpty())
34 this.attributes = Collections.emptyMap();
35 else
36 this.attributes = attributes;
37 }
38
39 public Container(Project project, File file) {
40 this(project, file.getName(), "project", TYPE.PROJECT, file, null, null);
41 }
42
43 public Container(File file) {
44 this(null, file.getName(), "project", TYPE.EXTERNAL, file, null, null);
45 }
46
47 public File getFile() {
48 return file;
49 }
50
51 /**
52 * Iterate over the containers and get the files they represent
53 *
54 * @param files
55 * @return
56 * @throws Exception
57 */
58 public boolean contributeFiles(List<File> files, Processor reporter) throws Exception {
59 switch (type) {
60 case EXTERNAL:
61 case REPO:
62 files.add(file);
63 return true;
64
65 case PROJECT:
66 File[] fs = project.build();
67 reporter.getInfo(project);
68 if (fs == null)
69 return false;
70
71 for (File f : fs)
72 files.add(f);
73 return true;
74
75 case LIBRARY:
76 List<Container> containers = getMembers();
77 for (Container container : containers) {
78 if (!container.contributeFiles(files, reporter))
79 return false;
80 }
81 return true;
82
83 case ERROR:
84 reporter.error(error);
85 return false;
86 }
87 return false;
88 }
89
90 public String getBundleSymbolicName() {
91 return bsn;
92 }
93
94 public String getVersion() {
95 return version;
96 }
97
98 public TYPE getType() {
99 return type;
100 }
101
102 public String getError() {
103 return error;
104 }
105
106 public boolean equals(Object other) {
107 if (other instanceof Container)
108 return file.equals(((Container) other).file);
109 else
110 return false;
111 }
112
113 public int hashCode() {
114 return file.hashCode();
115 }
116
117 public Project getProject() {
118 return project;
119 }
120
121 /**
122 * Must show the file name or the error formatted as a file name
123 *
124 * @return
125 */
126 public String toString() {
127 if (getError() != null)
128 return "/error/" + getError();
129 else
130 return getFile().getAbsolutePath();
131 }
132
133 public Map<String, String> getAttributes() {
134 return attributes;
135 }
136
137 public void putAttribute(String name, String value) {
138 if (attributes == Collections.<String,String>emptyMap())
139 attributes = new HashMap<String, String>(1);
140 attributes.put(name, value);
141 }
142
143 /**
144 * Return the this if this is anything else but a library. If it is a
145 * library, return the members. This could work recursively, e.g., libraries
146 * can point to libraries.
147 *
148 * @return
149 * @throws Exception
150 */
151 public List<Container> getMembers() throws Exception {
152 List<Container> result = project.newList();
153
154 // Are ww a library? If no, we are the result
155 if (getType() == TYPE.LIBRARY) {
156 // We are a library, parse the file. This is
157 // basically a specification clause per line.
158 // I.e. you can do bsn; version, bsn2; version. But also
159 // spread it out over lines.
160 InputStream in = new FileInputStream(file);
161 BufferedReader rd = new BufferedReader(new InputStreamReader(in,
162 Constants.DEFAULT_CHARSET));
163 try {
164 String line;
165 while ((line = rd.readLine()) != null) {
166 line = line.trim();
167 if (!line.startsWith("#") && line.length() > 0) {
168 List<Container> list = project.getBundles(Strategy.HIGHEST, line, null);
169 result.addAll(list);
170 }
171 }
172 } finally {
173 in.close();
174 }
175 } else
176 result.add(this);
177
178 return result;
179 }
180
181 /**
182 * Answer the manifest for this container (if possible). Manifest is cached
183 * until the file is renewed.
184 */
185
186 public Manifest getManifest() throws Exception {
187 if (getError() != null || getFile() == null)
188 return null;
189
190 if (manifestTime < getFile().lastModified()) {
191 InputStream in = new FileInputStream(getFile());
192 try {
193 JarInputStream jin = new JarInputStream(in);
194 manifest = jin.getManifest();
195 jin.close();
196 manifestTime = getFile().lastModified();
197 } finally {
198 in.close();
199 }
200 }
201 return manifest;
202 }
203}