Statistics
| Revision:

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
}