blob: 58b09c72defeeb50580e532aee6f9a9f68413f48 [file] [log] [blame]
Richard S. Hall7d1b9222006-10-30 16:36:04 +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
Richard S. Hall126a6392006-06-15 10:11:26 +00009 *
Richard S. Hall7d1b9222006-10-30 16:36:04 +000010 * http://www.apache.org/licenses/LICENSE-2.0
Richard S. Hall126a6392006-06-15 10:11:26 +000011 *
Richard S. Hall7d1b9222006-10-30 16:36:04 +000012 * 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.
Richard S. Hall126a6392006-06-15 10:11:26 +000018 */
Richard S. Hall7fa14152006-06-14 15:22:03 +000019package org.apache.felix.ipojo.plugin;
20
21import java.io.*;
22import java.util.*;
23import java.util.jar.*;
24import java.util.zip.*;
25
26public class Jar {
27 Map resources = new TreeMap();
28 Map imports = new HashMap();
29 Map exports = new HashMap();
30 Manifest manifest;
31 boolean manifestFirst;
32 String name;
33 Jar parent;
34 List activators = new ArrayList();
35
36 public Jar(Jar parent, String name, InputStream in) throws IOException {
37 this.name = name;
38 this.parent = parent;
39 ZipInputStream jar = new ZipInputStream(in);
40 ZipEntry entry = jar.getNextEntry();
41 boolean first = true;
42 while (entry != null) {
43 String path = entry.getName();
44
45 if (path.endsWith(".class")) {
46 Clazz clazz = new Clazz(this, path, jar);
47 resources.put(path, clazz);
48 }
49 else if (path.endsWith(".jar")) {
50 Jar pool = new Jar(this, path, jar);
51 resources.put(path, pool);
52 }
53 else if (path.endsWith("/packageinfo")
54 && !path.startsWith("OSGI-OPT")) {
55 String version = parsePackageInfo(jar, exports);
56 resources.put(path, version);
57 }
58 else if (path.equals("META-INF/MANIFEST.MF")) {
59 manifestFirst = first;
60 manifest = new Manifest(jar);
61 }
62 else
63 resources.put(path, null);
64
65 entry = jar.getNextEntry();
66 if (!path.endsWith("/"))
67 first = false;
68 }
69 }
70
71 public Jar(Jar parent, String name, File rootDir) throws IOException {
72 this.name = name;
73 this.parent = parent;
74 traverse(rootDir.getAbsolutePath().length(), rootDir, rootDir.list());
75 }
76
77 void traverse(int root, File dir, String list[]) throws IOException {
78 for (int i = 0; i < list.length; i++) {
79 File sub = new File(dir, list[i]);
80 if (sub.isDirectory())
81 traverse(root, sub, sub.list());
82 else {
83 String path = sub.getAbsolutePath().substring(root + 1)
84 .replace(File.separatorChar, '/');
85 FileInputStream in = new FileInputStream(sub);
86
87 if (path.endsWith(".class")) {
88 Clazz clazz = new Clazz(this, path, in);
89 resources.put(path, clazz);
90 }
91 else if (path.endsWith(".jar")) {
92 Jar pool = new Jar(this, path, in);
93 resources.put(path, pool);
94 }
95 else if (path.endsWith("/packageinfo")
96 && !path.startsWith("OSGI-OPT")) {
97 String version = parsePackageInfo(in, exports);
98 resources.put(path, version);
99 }
100 else if (path.endsWith("META-INF/MANIFEST.MF")) {
101 manifest = new Manifest(in);
102 }
103 else
104 resources.put(path, null);
105 }
106 }
107 }
108
109 private static String parsePackageInfo(InputStream jar, Map exports)
110 throws IOException {
111 try {
112 byte[] buf = collect(jar, 0);
113 String line = new String(buf);
114 StringTokenizer qt = new StringTokenizer(line, " \r\n\t");
115 if (qt.hasMoreElements()) {
116 qt.nextToken();
117 if (qt.hasMoreElements()) {
118 String version = qt.nextToken();
119 return version;
120 }
121 }
122 }
123 catch (Exception e) {
124 e.printStackTrace();
125 }
126 return null;
127 }
128
129 /**
130 * Convenience method to turn an inputstream into a byte array. The method
131 * uses a recursive algorithm to minimize memory usage.
132 *
133 * @param in stream with data
134 * @param offset where we are in the stream
135 * @returns byte array filled with data
136 */
137 private static byte[] collect(InputStream in, int offset)
138 throws IOException {
139 byte[] result;
140 byte[] buffer = new byte[10000];
141 int size = in.read(buffer);
142 if (size <= 0)
143 return new byte[offset];
144 else
145 result = collect(in, offset + size);
146 System.arraycopy(buffer, 0, result, offset, size);
147 return result;
148 }
149
150 public Manifest getManifest() {
151 return manifest;
152 }
153
154 public Object getEntry(String resource) {
155 return resources.get(resource);
156 }
157
158 public boolean exists(String jarOrDir) {
159 return resources.keySet().contains(jarOrDir);
160 }
161
162 public Set getEntryPaths(String prefix) {
163 Set result = new TreeSet();
164 for (Iterator i = resources.keySet().iterator(); i.hasNext();) {
165 String path = (String) i.next();
166 if (path.startsWith(prefix))
167 result.add(path);
168 }
169 return result;
170 }
171
172 String getName() {
173 return name;
174 }
175
176 public String toString() {
177 return getName();
178 }
179
180 public void addActivator(String path) {
181 if (parent != null)
182 parent.addActivator(path);
183 else {
184 activators.add(path);
185 }
186
187 }
188
189 public boolean containsActivator(String path) {
190 if (parent != null)
191 return parent.containsActivator(path);
192 return activators.contains(path);
193 }
194}