svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.library / org.gvsig.installer / org.gvsig.installer.lib / org.gvsig.installer.lib.impl / src / main / java / org / gvsig / installer / lib / impl / DependenciesCalculatorV2.java @ 40967
History | View | Annotate | Download (11.8 KB)
1 |
package org.gvsig.installer.lib.impl; |
---|---|
2 |
|
3 |
import java.util.ArrayList; |
4 |
import java.util.Collection; |
5 |
import java.util.Collections; |
6 |
import java.util.Comparator; |
7 |
import java.util.Iterator; |
8 |
import java.util.List; |
9 |
|
10 |
import org.gvsig.installer.lib.api.Dependencies; |
11 |
import org.gvsig.installer.lib.api.DependenciesCalculator; |
12 |
import org.gvsig.installer.lib.api.Dependency; |
13 |
import org.gvsig.installer.lib.api.PackageInfo; |
14 |
import org.gvsig.installer.lib.api.Version; |
15 |
import org.gvsig.installer.lib.api.execution.InstallPackageService; |
16 |
import org.gvsig.tools.packageutils.StringWithAlias; |
17 |
import org.slf4j.Logger; |
18 |
import org.slf4j.LoggerFactory; |
19 |
|
20 |
@SuppressWarnings("deprecation") |
21 |
public class DependenciesCalculatorV2 implements DependenciesCalculator { |
22 |
|
23 |
private static Logger logger = LoggerFactory |
24 |
.getLogger(DefaultDependenciesCalculator.class); |
25 |
|
26 |
private InstallPackageService installService = null; |
27 |
private List<PackageInfo> packagesInstalleds = null; |
28 |
private List<PackageInfo> packagesToInstall = null; |
29 |
private List<PackageInfo> requieredPackages = null; |
30 |
private List<PackageInfo> conflictsPackages = null; |
31 |
private Dependencies unresolvedDependencies = null; |
32 |
|
33 |
public DependenciesCalculatorV2(InstallPackageService installService) {
|
34 |
super();
|
35 |
this.installService = installService;
|
36 |
this.packagesInstalleds = new ArrayList<PackageInfo>(); |
37 |
this.packagesToInstall = new ArrayList<PackageInfo>(); |
38 |
} |
39 |
public void addPackageToInstall(PackageInfo packageInfo) { |
40 |
this.packagesToInstall.add(packageInfo);
|
41 |
} |
42 |
|
43 |
public void addPackageToInstall(Collection<PackageInfo> packages) { |
44 |
Iterator<PackageInfo> it = packages.iterator();
|
45 |
while (it.hasNext()) {
|
46 |
this.addPackageToInstall(it.next());
|
47 |
} |
48 |
} |
49 |
|
50 |
public void addInstalledPackage(PackageInfo packageInfo) { |
51 |
this.packagesInstalleds.add(packageInfo);
|
52 |
} |
53 |
|
54 |
public void addInstalledPackage(PackageInfo[] packages) { |
55 |
for (int i = 0; i < packages.length; i++) { |
56 |
this.addInstalledPackage(packages[i]);
|
57 |
} |
58 |
} |
59 |
|
60 |
public List<PackageInfo> getRequiredPackages() { |
61 |
return this.requieredPackages; |
62 |
} |
63 |
|
64 |
public List<PackageInfo> getConflictPackages() { |
65 |
return this.conflictsPackages; |
66 |
} |
67 |
|
68 |
public Dependencies getUnresolvedDependencies() {
|
69 |
return this.unresolvedDependencies; |
70 |
} |
71 |
|
72 |
private class DependencyAndPackages implements Dependency { |
73 |
|
74 |
private List<PackageInfo> packages = null; |
75 |
private Dependency delegate = null; |
76 |
|
77 |
DependencyAndPackages(Dependency dependency, PackageInfo packageInfo) { |
78 |
this.delegate = dependency;
|
79 |
this.packages = new ArrayList<PackageInfo>(); |
80 |
this.packages.add(packageInfo);
|
81 |
} |
82 |
|
83 |
public List<PackageInfo> getPackages() { |
84 |
return this.packages; |
85 |
} |
86 |
|
87 |
public void addPackage(PackageInfo packageInfo) { |
88 |
if( this.packages.contains(packageInfo)) { |
89 |
return;
|
90 |
} |
91 |
this.packages.add(packageInfo);
|
92 |
} |
93 |
|
94 |
public Dependency parse(String dependency) { |
95 |
return this.delegate.parse(dependency); |
96 |
} |
97 |
|
98 |
public String getType() { |
99 |
return this.delegate.getType(); |
100 |
} |
101 |
|
102 |
public String getCode() { |
103 |
return this.delegate.getCode(); |
104 |
} |
105 |
|
106 |
public String getOp() { |
107 |
return this.delegate.getOp(); |
108 |
} |
109 |
|
110 |
public Version getVersion() {
|
111 |
return this.delegate.getVersion(); |
112 |
} |
113 |
|
114 |
public boolean match(String type, String code, Version version) { |
115 |
return this.delegate.match(type, code, version); |
116 |
} |
117 |
|
118 |
public boolean match(String type, StringWithAlias code, Version version) { |
119 |
return this.delegate.match(type, code, version); |
120 |
} |
121 |
public Object clone() throws CloneNotSupportedException { |
122 |
DependencyAndPackages x = (DependencyAndPackages) super.clone();
|
123 |
x.packages = new ArrayList<PackageInfo>(); |
124 |
for (PackageInfo packageInfo : this.packages) { |
125 |
x.packages.add(packageInfo); |
126 |
} |
127 |
return x;
|
128 |
} |
129 |
|
130 |
public String toString() { |
131 |
StringBuffer buffer = new StringBuffer(); |
132 |
buffer.append( this.delegate.toString() );
|
133 |
buffer.append(" ( ");
|
134 |
for (PackageInfo packageInfo : this.packages) { |
135 |
buffer.append(packageInfo.getCode()); |
136 |
buffer.append(" ");
|
137 |
} |
138 |
buffer.append(" )");
|
139 |
return buffer.toString();
|
140 |
} |
141 |
|
142 |
} |
143 |
|
144 |
public void calculate() { |
145 |
int retryCount = 1; |
146 |
boolean retry = true; |
147 |
|
148 |
this.conflictsPackages = new ArrayList<PackageInfo>(); |
149 |
this.requieredPackages = new ArrayList<PackageInfo>(); |
150 |
this.unresolvedDependencies = new DefaultDependencies(); |
151 |
|
152 |
if( logger.isInfoEnabled() ) {
|
153 |
logger.info("Installeds packages:\n" + dumpPackages(this.packagesInstalleds)); |
154 |
logger.info("Packages to install:\n" + dumpPackages(this.packagesToInstall)); |
155 |
} |
156 |
while( retry ) {
|
157 |
if( retryCount > 50 ) { |
158 |
logger.info("Too many retries to calculate dependencies.");
|
159 |
throw new RuntimeException("Too many retries to calculate dependencies"); |
160 |
} |
161 |
/*
|
162 |
* Inicializamos el conjunto de paquetes que al final han de quedar
|
163 |
* instalados con:
|
164 |
* - Los paqetes ya instalados
|
165 |
* - Los paquetes que hay que instalar
|
166 |
* - Los paquetes que hay que instalar por que son depenendencia de
|
167 |
* alguno instalado o a instalar.
|
168 |
*/
|
169 |
List<PackageInfo> packages = new ArrayList<PackageInfo>(); |
170 |
packages.addAll(this.packagesInstalleds);
|
171 |
packages.addAll(this.packagesToInstall);
|
172 |
packages.addAll(this.requieredPackages);
|
173 |
|
174 |
/*
|
175 |
* Una vez tenemos la lista de paquetes que han de quedar instalados,
|
176 |
* Creamos la lista de dependencias de todos los paquetes.
|
177 |
*/
|
178 |
Dependencies dependencies = new DefaultDependencies();
|
179 |
for (PackageInfo packageInfo : packages) {
|
180 |
Dependencies pkgDependencies = packageInfo.getDependencies(); |
181 |
for( int i=0; i< pkgDependencies.size(); i++) { |
182 |
Dependency dependency = (Dependency) pkgDependencies.get(i); |
183 |
List x = dependencies.findAll( dependency.getType(), dependency.getCode(), dependency.getVersion());
|
184 |
if( x == null ) { |
185 |
dependencies.add(new DependencyAndPackages(dependency,packageInfo));
|
186 |
} else if(x.size()==1) { |
187 |
((DependencyAndPackages)x.get(0)).addPackage(packageInfo);;
|
188 |
} else {
|
189 |
// Hay paquetes que tienen dependencias con el mismo paquete pero
|
190 |
// con versiones distintas. Cogemos la version mayor.
|
191 |
Collections.sort(x, new Comparator<Dependency>() { |
192 |
public int compare(Dependency arg0, Dependency arg1) { |
193 |
// Orden inverso, la primera la mas alta
|
194 |
return - arg0.getVersion().compareTo(arg1.getVersion());
|
195 |
} |
196 |
}); |
197 |
((DependencyAndPackages)x.get(0)).addPackage(packageInfo);;
|
198 |
|
199 |
} |
200 |
} |
201 |
} |
202 |
// if( logger.isInfoEnabled() ) {
|
203 |
// logger.info("Attempt: " + retryCount);
|
204 |
// logger.info("Required packages:\n" + dumpPackages(this.requieredPackages));
|
205 |
// logger.info("Unresolved dependencies:\n" + dumpDependencies(this.unresolvedDependencies));
|
206 |
// logger.info("Conflict packages:\n" + dumpPackages(this.conflictsPackages));
|
207 |
// logger.info("All dependencies:\n" + dumpDependencies(dependencies));
|
208 |
// }
|
209 |
|
210 |
/*
|
211 |
* Ahora calcularemos si se cumplen esas dependencias, y en caso de que no
|
212 |
* si tenemos el paquete que se corresponde con esa dependencia.
|
213 |
* Si se a?ade un paquete a instalar debido a que es dependencia de otro,
|
214 |
* deberemos recalcular las dependencias de nuevo y reintentarlo para ver
|
215 |
* si este nuevo paquete a introducido nuevas dependencias.
|
216 |
*/
|
217 |
retry = calculateRequiredPackagesAndUnresolvedDependencies(dependencies); |
218 |
if( retry ) {
|
219 |
retryCount +=1;
|
220 |
} else {
|
221 |
calculateConflictPackages(dependencies); |
222 |
} |
223 |
} |
224 |
|
225 |
// Ordenamos los resultados para hacer previsible y repetibles los resultados.
|
226 |
if( this.requieredPackages!=null && !this.requieredPackages.isEmpty() ) { |
227 |
Collections.sort(this.requieredPackages, new Comparator<PackageInfo>() { |
228 |
public int compare(PackageInfo o1, PackageInfo o2) { |
229 |
return o1.getCode().compareTo(o2.getCode());
|
230 |
} |
231 |
}); |
232 |
} |
233 |
if( this.conflictsPackages!=null && !this.conflictsPackages.isEmpty() ) { |
234 |
Collections.sort(this.conflictsPackages, new Comparator<PackageInfo>() { |
235 |
public int compare(PackageInfo o1, PackageInfo o2) { |
236 |
return o1.getCode().compareTo(o2.getCode());
|
237 |
} |
238 |
}); |
239 |
} |
240 |
if( this.unresolvedDependencies!=null && !this.unresolvedDependencies.isEmpty() ) { |
241 |
Collections.sort(this.unresolvedDependencies, new Comparator<Dependency>() { |
242 |
public int compare(Dependency o1, Dependency o2) { |
243 |
return o1.getCode().compareTo(o2.getCode());
|
244 |
} |
245 |
}); |
246 |
} |
247 |
|
248 |
if( logger.isInfoEnabled() ) {
|
249 |
logger.info("Required packages:\n" + dumpPackages(this.requieredPackages)); |
250 |
logger.info("Unresolved dependencies:\n" + dumpDependencies(this.unresolvedDependencies)); |
251 |
logger.info("Conflict packages:\n" + dumpPackages(this.conflictsPackages)); |
252 |
logger.info("Attempts Requireds: " + retryCount);
|
253 |
} |
254 |
} |
255 |
|
256 |
private boolean calculateRequiredPackagesAndUnresolvedDependencies(Dependencies dependencies) { |
257 |
boolean retry = false; |
258 |
for( int i=0; i<dependencies.size(); i++ ) { |
259 |
DependencyAndPackages dependency = (DependencyAndPackages) dependencies.get(i); |
260 |
if( Dependency.REQUIRED.equals(dependency.getType()) ) {
|
261 |
PackageInfo availablePackage = getInstalledOrToInstallOrRequiredsPackage(dependency); |
262 |
if( availablePackage==null ) { |
263 |
availablePackage = getAvalible(dependency); |
264 |
if( availablePackage != null ) { |
265 |
logger.info("Added new package "+availablePackage.getCode()+" required by dependency "+dependency.toString()+"."); |
266 |
this.requieredPackages.add(availablePackage);
|
267 |
/*
|
268 |
* Al a?adir paquetes nuevos, debemos recualcular las
|
269 |
* dependencias de nuevo y volver a comprobar si se cumplen.
|
270 |
*/
|
271 |
retry = true;
|
272 |
} else {
|
273 |
this.unresolvedDependencies.add(dependency);
|
274 |
} |
275 |
} |
276 |
} |
277 |
} |
278 |
return retry;
|
279 |
} |
280 |
|
281 |
private void calculateConflictPackages(Dependencies dependencies) { |
282 |
for( int i=0; i<dependencies.size(); i++ ) { |
283 |
DependencyAndPackages dependency = (DependencyAndPackages) dependencies.get(i); |
284 |
if( Dependency.CONFLICT.equals(dependency.getType()) ) {
|
285 |
PackageInfo pkg = getInstalledOrToInstallOrRequiredsPackage(dependency); |
286 |
if( pkg != null ) { |
287 |
this.conflictsPackages.addAll(dependency.getPackages());
|
288 |
} |
289 |
} |
290 |
} |
291 |
} |
292 |
|
293 |
/**
|
294 |
* Busca entre los paquetes instalados o a instalar alguno que
|
295 |
* se corresponda con los requerimientos de la dependencia y lo
|
296 |
* devuelve. Devuelve null si no lo encuentra.
|
297 |
*
|
298 |
* @param dependency
|
299 |
* @return the package that match with the dependency or null
|
300 |
*/
|
301 |
private PackageInfo getInstalledOrToInstallOrRequiredsPackage(
|
302 |
DependencyAndPackages dependency) { |
303 |
for (PackageInfo pkg : this.packagesInstalleds ) { |
304 |
if( dependency.match(dependency.getType(), pkg.getAllCodes(), pkg.getVersion())) {
|
305 |
return pkg;
|
306 |
} |
307 |
} |
308 |
for (PackageInfo pkg : this.packagesToInstall ) { |
309 |
if( dependency.match(dependency.getType(), pkg.getAllCodes(), pkg.getVersion())) {
|
310 |
return pkg;
|
311 |
} |
312 |
} |
313 |
for (PackageInfo pkg : this.requieredPackages ) { |
314 |
if( dependency.match(dependency.getType(), pkg.getAllCodes(), pkg.getVersion())) {
|
315 |
return pkg;
|
316 |
} |
317 |
} |
318 |
return null; |
319 |
} |
320 |
|
321 |
/**
|
322 |
* Busca entre los paquetes disponibles a ver si encuentra uno que se
|
323 |
* corresponda con los requerimientos de la dependencia y si lo encunetra
|
324 |
* lo devuelve. Si no devuelbe null.
|
325 |
*
|
326 |
* @param dependency
|
327 |
* @return the package that match with the dependency or null
|
328 |
*/
|
329 |
private PackageInfo getAvalible(DependencyAndPackages dependency) {
|
330 |
for (int i = 0; i < this.installService.getPackageCount(); i++) { |
331 |
PackageInfo pkg = this.installService.getPackageInfo(i);
|
332 |
if( dependency.match(dependency.getType(), pkg.getAllCodes(), pkg.getVersion())) {
|
333 |
return pkg;
|
334 |
} |
335 |
} |
336 |
return null; |
337 |
} |
338 |
|
339 |
private String dumpPackages(Collection<PackageInfo> pkgs) { |
340 |
StringBuffer s = new StringBuffer(); |
341 |
Iterator<PackageInfo> it = pkgs.iterator();
|
342 |
while (it.hasNext()) {
|
343 |
s.append(it.next().toStringCompact()); |
344 |
s.append("\n");
|
345 |
} |
346 |
|
347 |
return s.toString();
|
348 |
} |
349 |
|
350 |
private String dumpDependencies(Collection<Dependency> dependencies) { |
351 |
StringBuffer s = new StringBuffer(); |
352 |
Iterator<Dependency> it = dependencies.iterator();
|
353 |
while (it.hasNext()) {
|
354 |
s.append(it.next().toString()); |
355 |
s.append("\n");
|
356 |
} |
357 |
return s.toString();
|
358 |
} |
359 |
} |