View Javadoc

1   /*
2    *  XNap - A P2P framework and client.
3    *
4    *  See the file AUTHORS for copyright information.
5    *
6    *  This program is free software; you can redistribute it and/or modify
7    *  it under the terms of the GNU General Public License as published by
8    *  the Free Software Foundation.
9    *
10   *  This program is distributed in the hope that it will be useful,
11   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   *  GNU General Public License for more details.
14   *
15   *  You should have received a copy of the GNU General Public License
16   *  along with this program; if not, write to the Free Software
17   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18   */
19  
20  package org.xnap.pkg;
21  
22  import java.io.BufferedReader;
23  import java.io.BufferedWriter;
24  import java.io.File;
25  import java.io.FileInputStream;
26  import java.io.FileWriter;
27  import java.io.IOException;
28  import java.io.InputStream;
29  import java.io.InputStreamReader;
30  import java.net.URL;
31  import java.util.Hashtable;
32  import java.util.Iterator;
33  import java.util.LinkedList;
34  import java.util.Properties;
35  import java.util.*;
36  import java.util.StringTokenizer;
37  import java.util.TreeSet;
38  import java.util.zip.GZIPInputStream;
39  
40  /***
41   * 
42   */
43  public class PackageManager
44  {
45  
46      //--- Constant(s) ---
47  
48      //--- Data field(s) ---
49  
50  	/***
51  	 * A sorted list of PackageInfo objects.
52  	 */
53      privateong> TreeSet packages = new TreeSet();
54  	private> Hashtable packageListByProvides = new Hashtable();
55  
56      //--- Constructor(s) ---
57  
58  	public PackageManager()
59      {
60      }
61  
62      //--- Method(s) ---
63  
64  	/***
65  	 * Adds a package. If info is not valid or a package with the same
66  	 * name and version already exists the package is not added.
67  	 */
68  	public void add(PackageInfo info)
69  	{
70  		if (info.isValid()) {
71  			ifng> (packages.contains(info)) {
72  				SortedSet tailSet = packages.tailSet(info);
73  				PackageInfo old = (PackageInfo)tailSet.first();
74  				if (old.isInstalled()) {
75  					old.setAvailable(true);
76  					// do not update already installed package info
77  					return;
78  				}
79  				else {
80  					remove(old);
81  					info.setNew(old.isNew());
82  				}
83  			}
84  			packages.add(info);
85  			info.setAvailable(true);
86  
87  			if (info.getProvides() != null) {
88  				StringTokenizer t
89  					= new StringTokenizer(info.getProvides(), ",");
90  				while (t.hasMoreTokens()) {
91  					String name = t.nextToken().trim();
92  					LinkedList list
93  						= (LinkedList)packageListByProvides.get(name);
94  					if (list == null) {
95  						list = new LinkedList();
96  						packageListByProvides.put(name, list);
97  					}
98  					list.add(info);
99  				}
100 			}
101 		}
102 	}
103 
104 	public PackageInfo[] getConflicts(PackageInfo info)
105 		throws ParseException
106 	{
107 		LinkedList packageTokens = new LinkedList();
108 		DefaultDependencyParser parser = new DefaultDependencyParser();
109 		AbstractToken token = parser.parseConflicts(info);
110 		if (token instanceof CommaToken) {
111 			AbstractToken[] depends = ((CommaToken)token).depends;
112 			for (int i = 0; i < depends.length; i++) {
113 				if (depends[i] instanceof PackageToken) {
114 					packageTokens.add(depends[i]);
115 				}
116 			}
117 		}
118 		else if (token instanceof PackageToken) {
119 			packageTokens.add(token);
120 		}
121 
122 		LinkedList infos = new LinkedList();
123 		for (Iterator it = packageTokens.iterator(); it.hasNext();) {
124 			addConflicts(infos, (PackageToken)it.next());
125 		}
126 		return (PackageInfo[])infos.toArray(new PackageInfo[0]);
127 	}
128 
129 	private void addConflicts(List list, PackageToken token) 
130 	{
131 		// packages
132 		for (Iterator it = tailSet(token.name).iterator(); it.hasNext();) {
133 			PackageInfo info = (PackageInfo)it.next();
134 			if (info.getPackage().equals(token.name)) {
135 				if (token.compareMode == null
136 					|| token.equalsVersion(info.compareToVersion
137 										   (token.version))) {
138 					// get package node
139 					list.add(info);
140 				}
141 			}
142 			else {
143 				break;
144 			}
145 		}
146 	}
147 
148 	/***
149 	 * Returns a list of urls.
150 	 *
151 	 * @return the empty string
152 	 */
153 	public String getDefaultSources()
154 	{
155 		return "";
156 	}
157 
158 	/***
159 	 *
160 	 * @exception ParseException thrown, if package file is invalid
161 	 * @exception UnsatisfiedDependenciesException thrown, if
162 	 * dependencies are not satisfied
163 	 */
164 	public PackageInfo[] getDependencies(PackageInfo info)
165 		throws ParseException, UnsatisfiedDependenciesException
166 	{
167 		DependencyGraph graph = new DependencyGraph(this);
168 		graph.add(info);
169 		graph.buildDependencies(new DefaultDependencyParser());
170 
171 		DefaultResolver r = new DefaultResolver(graph, true);
172 		r.resolve();
173 		return r.getRequired();
174 	}
175 
176 	/***
177 	 * Marks all packages that are not installed as unavailable. Marks
178 	 * all packages as not new.
179 	 */
180 	public void markAllUnavailable()
181 	{
182 		for (Iterator i = packages(); i.hasNext();) {
183 			PackageInfo info = (PackageInfo)i.next();
184 			info.setAvailable(info.isInstalled());
185 			info.setNew(false);
186 		}
187 	}
188 
189 	/***
190 	 * Reads package information from a control file.
191 	 *
192 	 * @param file the control file
193 	 */
194 	public void read(File file, Properties table) throws IOException
195 	{
196 		FileInputStream in = new FileInputStream(file);
197 		try {
198 			read(in, table);
199 		}
200 		finally {
201 			in.close();
202 		}
203 	}
204 
205 	public void read(File file) throws IOException
206 	{
207 		read(file, null);
208 	}	
209 
210 	/***
211 	 * Reads package information from a url.
212 	 *
213 	 * @param location the package file url
214 	 * @param downloadUrl the base location of the package files
215 	 */
216 	public void read(String location, Properties table) throws IOException
217 	{
218 		URL url = new URL(location);
219 		InputStream in = url.openStream();
220 		try {
221 			if (location.endsWith(".gz")) {
222 				in = new GZIPInputStream(url.openStream());
223 			}
224 			read(in, table);
225 		}
226 		finally {
227 			in.close();
228 		}
229 	}
230 
231 	/***
232 	 * Reads package information from a stream.
233 	 *
234 	 * @param inStream the stream
235 	 * @param flags additional flags that are added to the {@link
236 	 * PackageInfo} record; if null, flags are ignored
237 	 */
238 	public void read(InputStream inStream, Properties flags)
239 		throws IOException
240 	{
241 		BufferedReader in 
242 			= new BufferedReader(new InputStreamReader(inStream));
243 
244 		Properties p;
245 		while ((p = PackageInfoReader.readNext(in)) != null) {
246 			PackageInfo info = new PackageInfo(p);
247 			if (flags != null) {
248 				info.putAll(flags);
249 			}
250 			add(info);
251 		}
252 	}
253 
254 	public void remove(PackageInfo info)
255 	{
256 		packages.remove(info);
257 		if (info.getProvides() != null) {
258 			StringTokenizer t
259 				= new StringTokenizer(info.getProvides(), ",");
260 			while (t.hasMoreTokens()) {
261 				String name = t.nextToken().trim();
262 				LinkedList list
263 					= (LinkedList)packageListByProvides.get(name);
264 				if (list != null) {
265 					list.remove(info);
266 				}
267 			}
268 		}
269 	}
270 
271 	/***
272 	 * Removes all packages that are marked as unavailable.
273 	 */
274 	public void removeUnavailable()
275 	{
276 		LinkedList toRemove = new LinkedList();
277 		for (Iterator i = packages(); i.hasNext();) {
278 			PackageInfo info = (PackageInfo)i.next();
279 			if (!(info.isInstalled() || info.isAvailable())) {
280 				toRemove.add(info);
281 			}
282 		}
283 
284 		for (Iterator i = toRemove.iterator(); i.hasNext();) {
285 			remove((PackageInfo)i.next());
286 		}
287 	}
288 
289 	/***
290 	 * Returns an iterator over all {@link PackageInfo} objects.
291 	 */
292 	public> Iterator packages()
293 	{
294 		returng> packages.iterator();
295 	}
296 
297 	/***
298 	 * Returns the number of packages.
299 	 */
300 	public int getPackageCount()
301 	{
302 		returng> packages.size();
303 	}
304 
305 	/***
306 	 * Returns a package by name.
307 	 */
308 	publicPackageInfo getPackage(String packageName)/package-summary.html">> PackageInfo getPackage(String packageName)
309 	{
310 			SortedSet set = tailSet(packageName);
311 			if (!set.isEmpty()) {
312 					PackageInfo info = (PackageInfo)set.first();
313 					ifrong> (info.getPackage().equals(packageName)) {
314 							return info;
315 					}
316 			}
317 				return null;
318 	}
319 
320 	public> SortedSet tailSet(String packageName)
321 	{
322 		returnPackageInfo(packageName))/package-summary.html">g> packages.tailSet(new PackageInfo(packageName));
323 	}
324 
325 	/***
326 	 * Returns an array of packages that provide packageName.
327 	 */
328 	publicPackageInfo[] getProviders(String packageName)/package-summary.html">> PackageInfo[] getProviders(String packageName)
329 	{
330 		LinkedList list = (LinkedList)packageListByProvides.get(packageName);
331 		return (list != null) 
332 			? (PackageInfo[])list.toArray(new PackageInfo[0]) 
333 			: null;
334 	}
335 
336 	public void write(File file, Properties flags) throws IOException
337 	{
338 		BufferedWriter out = new BufferedWriter(new FileWriter(file));
339 		try {
340 			for (Iterator i = packages.iterator(); i.hasNext();) {
341 				PackageInfo info = (PackageInfo)i.next();
342 				if (flags == null || info.containsProperties(flags)) {
343 					PackageInfoWriter.write(out, info.getProperties());
344 				}
345 			}
346 		}
347 		finally {
348 			try {
349 				out.close();
350 			}
351 			catch (IOException e) {
352 			}
353 		}		
354 	}
355 
356 }
357