Statistics
| Revision:

gvsig-tools / org.gvsig.tools / library / trunk / org.gvsig.tools / org.gvsig.tools.lib / src / main / java / org / gvsig / tools / library / AbstractLibrariesInitializer.java @ 1340

History | View | Annotate | Download (15.1 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 2
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
package org.gvsig.tools.library;
25

    
26
import java.text.MessageFormat;
27
import java.util.ArrayList;
28
import java.util.Collection;
29
import java.util.Comparator;
30
import java.util.HashSet;
31
import java.util.Iterator;
32
import java.util.LinkedList;
33
import java.util.List;
34
import java.util.Map;
35
import java.util.Set;
36
import java.util.TreeMap;
37

    
38
import org.slf4j.Logger;
39
import org.slf4j.LoggerFactory;
40

    
41
import org.gvsig.tools.exception.BaseRuntimeException;
42
import org.gvsig.tools.library.AbstractLibrary.DefaultRequired;
43
import org.gvsig.tools.library.Library.Required;
44

    
45
/**
46
 * Base implementation of an {@link LibrariesInitializer} with the
47
 * initialization of Libraries already implemented, delegating on child classes
48
 * the finding of available {@link Library} objects.
49
 * <p>
50
 * This class is NOT thread safe.
51
 * </p>
52
 * 
53
 * @author <a href="mailto:cordinyana@gvsig.org">C?sar Ordi?ana</a>
54
 */
55
public abstract class AbstractLibrariesInitializer implements
56
    LibrariesInitializer, Library.TYPE {
57

    
58
    private static final Logger LOG = LoggerFactory
59
        .getLogger(AbstractLibrariesInitializer.class);
60

    
61
    private Collection libs;
62

    
63
    private boolean libsLoaded = false;
64

    
65
    private final ClassLoader[] classLoaders;
66

    
67
    public AbstractLibrariesInitializer() {
68
        classLoaders = null;
69
    }
70

    
71
    public AbstractLibrariesInitializer(ClassLoader classLoader) {
72
        this(new ClassLoader[] { classLoader });
73
    }
74

    
75
    public AbstractLibrariesInitializer(ClassLoader[] classLoaders) {
76
        this.classLoaders = classLoaders;
77
    }
78

    
79
    public void initialize() {
80
        this.initialize(false);
81
    }
82

    
83
    public void initialize(boolean ignoreerrors) {
84
        if (!libsLoaded) {
85
            loadLibraries(classLoaders, ignoreerrors);
86
            libsLoaded = true;
87
        }
88
        if (libs != null && libs.size() > 0) {
89
            // Call all initialize()
90
            initializeLibraries(libs, false, ignoreerrors);
91
        }
92
    }
93

    
94
    public void postInitialize() {
95
        this.postInitialize(false);
96
    }
97

    
98
    public void postInitialize(boolean ignoreerrors) {
99
        if (!libsLoaded) {
100
            loadLibraries(classLoaders, ignoreerrors);
101
            libsLoaded = true;
102
        }
103
        if (libs != null && libs.size() > 0) {
104
            // Call all postInitialize()
105
            initializeLibraries(libs, true, ignoreerrors);
106
        }
107
    }
108

    
109
    public void fullInitialize() {
110
        initialize();
111
        postInitialize();
112
    }
113

    
114
    public void fullInitialize(boolean ignoreerrors) {
115
        initialize(ignoreerrors);
116
        postInitialize(ignoreerrors);
117
    }
118

    
119
    public List getLibraries() {
120
        if (!libsLoaded) {
121
            loadLibraries(classLoaders, false);
122
            libsLoaded = true;
123
        }
124

    
125
        return new ArrayList(this.libs);
126
    }
127

    
128
    private void loadLibraries(ClassLoader[] classLoaders, boolean ignoreerrors) {
129
        // Find the available Library instances
130
        Set<Library> libs = new HashSet<>();
131
        LOG.info("Loading libraries of classloaders:");
132
        if (classLoaders == null) {
133
            addLibrariesOfClassLoader(libs, null, ignoreerrors);
134
        } else {
135
            for (int i = 0; i < classLoaders.length; i++) {
136
                addLibrariesOfClassLoader(libs, classLoaders[i], ignoreerrors);
137
            }
138
        }
139
        
140
        this.updateRequireds(libs);
141
        
142
        int fullSize = libs.size();
143
        this.libs = new OrderedLibs(libs);
144

    
145
        if (LOG.isInfoEnabled()) {
146
            logLibraries(this.libs, fullSize);
147
        }
148
    }
149

    
150
    private void updateRequireds(Set<Library> libs) {
151
        for( int retries=0; retries<10; retries++ ) {
152
            boolean updated = false;
153
            for (Library lib : libs) { 
154
                Set<Required> r0 = lib.getRequireds();
155
                if( r0!=null ) {
156
                    List<Required> r1 = new ArrayList(r0);
157
                    int count = r1.size();
158
                    for (Required required : r1) {
159
                        Library requiredLibrary = required.getLibrary(libs);
160
                        if( requiredLibrary!= null ) {
161
                            Set<Required> requireds = requiredLibrary.getRequireds();
162
                            if( requireds != null ) {
163
                                lib.require(requireds);
164
                            }
165
                        }
166
                    }
167
                    if( count != lib.getRequireds().size() ) {
168
                        updated = true;
169
                    }
170
                }
171
            }
172
            if( !updated ) {
173
                break;
174
            }
175
        }
176
        if( LOG.isDebugEnabled() ) {
177
            for (Library lib : libs) {
178
                LOG.trace("Library: "+lib.getClass().getName());
179
                Set<Required> r0 = lib.getRequireds();
180
                if( r0!=null ) {
181
                    for (Required required : r0) {
182
                        LOG.trace("  require "+required.toString());
183
                    }
184
                }
185
            }
186
        }
187
    }
188
    
189
    private void addLibrariesOfClassLoader(Set previousFoundLibs,
190
        ClassLoader classLoader, boolean ignoreerrors) {
191
        StringBuffer logBuf = new StringBuffer();
192
        Library library = null;
193
        try {
194
            Set foundLibs = findLibraries(Library.class, classLoader);
195
            foundLibs.removeAll(previousFoundLibs);
196
            logBuf
197
                .append(new Integer(foundLibs.size()))
198
                .append(" new libraries found in the classloader ")
199
                .append(
200
                    classLoader == null ? "DEFAULT" : classLoader.toString())
201
                .append(":");
202

    
203
            for (Iterator iterator = foundLibs.iterator(); iterator.hasNext();) {
204
                library = (Library) iterator.next();
205
                try {
206
                    library.doRegistration();
207
                } catch (Throwable e) {
208
                    manageLibraryException(ignoreerrors, "doRegistration",
209
                        library, e);
210
                }
211
                previousFoundLibs.add(library);
212
                logBuf.append("\n- ").append(library);
213
            }
214
            
215
        } catch (Exception e) {
216
            String msg =
217
                MessageFormat.format(
218
                    "Error finding libraries of classloader {0}. Last procesed library {1}.",
219
                    new String[] { 
220
                        classLoader == null ? "DEFAULT" : classLoader.toString(),
221
                        library == null ? "(no-library)" : library.toString(),
222
                    }
223
                );
224
            manageLibraryException(ignoreerrors, msg, e);
225
        } finally {
226
            try {
227
                LOG.info(logBuf.toString());
228
            } catch(Throwable th) {
229
                // Ignore errors.
230
            }
231
        }
232
    }
233

    
234
    protected abstract Set findLibraries(Class libraryClass,
235
        ClassLoader classLoader);
236

    
237
    private void initializeLibraries(Collection libs, boolean post,
238
        boolean ignoreerrors) {
239
        String label;
240
        if (post) {
241
            label = "postInitialize";
242
        } else {
243
            label = "initialize";
244
        }
245

    
246
        for (Iterator iterator = libs.iterator(); iterator.hasNext();) {
247
            Library lib = (Library) iterator.next();
248
            try {
249
                if (post) {
250
                    LOG.trace("Calling {}.postInitialize()", lib.getClass()
251
                        .getName());
252
                    lib.postInitialize();
253
                } else {
254
                    LOG.trace("Calling {}.initialize()", lib.getClass()
255
                        .getName());
256
                    lib.initialize();
257
                }
258
            } catch (Throwable e) {
259
                manageLibraryException(ignoreerrors, label, lib, e);
260
            }
261
        }
262
    }
263

    
264
    private void manageLibraryException(boolean ignoreerrors, String label,
265
        Library lib, Throwable e) {
266
        String msg;
267
        if (e instanceof BaseRuntimeException) {
268
            msg = ((BaseRuntimeException) e).getLocalizedMessageStack();
269
        } else {
270
            msg = e.getLocalizedMessage();
271
        }
272
        String formattedMsg =
273
            MessageFormat.format("Error in {0} of library {1}. {2}",
274
                new String[] { label, lib.getClass().getName(), msg });
275
        manageLibraryException(ignoreerrors, formattedMsg, e);
276
    }
277

    
278
    private void manageLibraryException(boolean ignoreerrors, String message,
279
        Throwable e) {
280
        if (ignoreerrors) {
281
            LOG.error(message, e);
282
        } else {
283
            if (e instanceof RuntimeException) {
284
                throw (RuntimeException) e;
285
            } else if (e instanceof Error) {
286
                throw (Error) e;
287
            }
288
        }
289
    }
290

    
291
    private void logLibraries(Collection libs, int fullSize) {
292
        StringBuffer buffer = new StringBuffer();
293
        buffer.append("Total libraries to initialize (")
294
            .append(libs == null ? 0 : libs.size()).append(" of ")
295
            .append(fullSize).append("):");
296
        if (libs != null) {
297
            for (Iterator iterator = libs.iterator(); iterator.hasNext();) {
298
                buffer.append("\n- ").append(iterator.next());
299
            }
300
        }
301
        LOG.info(buffer.toString());
302
    }
303

    
304
    private static class OrderedLibs extends ArrayList {
305

    
306
        private static final long serialVersionUID = -8546268624773345053L;
307

    
308
        // By default order alphabetically
309
        private Map apis;
310

    
311
        public OrderedLibs(Set libs) {
312
            apis = new TreeMap(new Comparator() {
313

    
314
                public int compare(Object o1, Object o2) {
315
                    Class class1 = (Class) o1;
316
                    Class class2 = (Class) o2;
317
                    return class1.getName().compareTo(class2.getName());
318
                }
319
            });
320
            orderLibs(libs);
321
        }
322

    
323
        private void orderLibs(Set libs) {
324
            // First create the groups of libraries, internally ordered:
325
            // 1: api, 2: impl, 3: serv1, 4: serv2, ...
326
            // (servs ordered by dependency)
327
            for (Iterator iterator = libs.iterator(); iterator.hasNext();) {
328
                Library library = (Library) iterator.next();
329
                Class API = library.getLibrary();
330
                if (API == null) {
331
                    API = library.getClass();
332
                }
333
                List libraryGroup = (List) apis.get(API);
334
                if (libraryGroup == null) {
335
                    libraryGroup = new LinkedList();
336
                    apis.put(API, libraryGroup);
337
                }
338
                addLibraryToGroup(libraryGroup, library);
339
            }
340

    
341
            Set alreadyAddedGroups = new HashSet();
342
            for (Iterator iterator = apis.keySet().iterator(); iterator
343
                .hasNext();) {
344
                Class APIRequired = (Class) iterator.next();
345
                addFromLibraryGroup(APIRequired, alreadyAddedGroups);
346
            }
347
        }
348

    
349
        private void addLibraryToGroup(List libraryGroup, Library library) {
350
            String type = library.getType();
351

    
352
            // If first, don't look anything else and add it
353
            if (libraryGroup.isEmpty()) {
354
                libraryGroup.add(library);
355
                return;
356
            }
357

    
358
            if (API.equals(type)) {
359
                // API library must go first
360
                libraryGroup.add(0, library);
361
            } else if (IMPL.equals(type)) {
362
                // Look for other implementation an replace it if priority
363
                // is higher, or discard
364
                for (int i = 0; i < libraryGroup.size(); i++) {
365
                    Library current = (Library) libraryGroup.get(i);
366
                    if (IMPL.equals(current.getType())) {
367
                        if (current.getPriority() < library.getPriority()) {
368
                            libraryGroup.set(i, library);
369
                            return;
370
                        } else {
371
                            return;
372
                        }
373
                    }
374
                }
375
                // If it is the first implementation, insert it after the API
376
                // and before the services, if any.
377
                Library first = (Library) libraryGroup.get(0);
378
                if (API.equals(first.getType())) {
379
                    if (libraryGroup.size() == 1) {
380
                        libraryGroup.add(library);
381
                    } else {
382
                        libraryGroup.add(1, library);
383
                    }
384
                    return;
385
                } else {
386
                    libraryGroup.add(0, library);
387
                    return;
388
                }
389
            } else { // It is a service type
390
                // Look for other services and insert by dependency order
391
                for (int i = 0; i < libraryGroup.size(); i++) {
392
                    Library current = (Library) libraryGroup.get(i);
393
                    if (SERVICE.equals(current.getType())) {
394
                        if (current.isRequired(library)) {
395
                            libraryGroup.add(i, library);
396
                            return;
397
                        }
398
                    }
399
                }
400
                // Otherwise add the last
401
                libraryGroup.add(library);
402
            }
403
        }
404

    
405
        private void addFromLibraryGroup(Class APIRequired,
406
            Set alreadyAddedGroups) {
407
            Collection libraryGroup = (Collection) apis.get(APIRequired);
408
            if (libraryGroup != null
409
                && !alreadyAddedGroups.contains(APIRequired)) {
410
                alreadyAddedGroups.add(APIRequired);
411

    
412
                // Add all group libraries, taking into account dependencies
413
                // with other library groups
414
                for (Iterator iterator = libraryGroup.iterator(); iterator
415
                    .hasNext();) {
416
                    Library library = (Library) iterator.next();
417
                    Set requireds = library.getRequireds();
418
                    if (requireds != null) {
419
                        for (Iterator requiredsIter = requireds.iterator(); requiredsIter
420
                            .hasNext();) {
421
                            DefaultRequired required = (DefaultRequired) requiredsIter.next();
422
                            addFromLibraryGroup(required.getLibraryClass(),
423
                                alreadyAddedGroups);
424
                        }
425
                    }
426
                    add(library);
427
                }
428
            }
429
        }
430

    
431
    }
432

    
433
}