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 @ 655

History | View | Annotate | Download (13.1 KB)

1
/* gvSIG. Geographic Information System of the Valencian Government
2
 *
3
 * Copyright (C) 2007-2008 Infrastructures and Transports Department
4
 * of the Valencian Government (CIT)
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
 */
22

    
23
package org.gvsig.tools.library;
24

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

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

    
40
import org.gvsig.tools.exception.BaseRuntimeException;
41
import org.gvsig.tools.library.AbstractLibrary.Required;
42

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

    
56
    private static final Logger LOG = LoggerFactory
57
        .getLogger(AbstractLibrariesInitializer.class);
58

    
59
    private Collection libs;
60

    
61
    private boolean libsLoaded = false;
62

    
63
    private final ClassLoader[] classLoaders;
64

    
65
    public AbstractLibrariesInitializer() {
66
        classLoaders = null;
67
    }
68

    
69
    public AbstractLibrariesInitializer(ClassLoader classLoader) {
70
        this(new ClassLoader[] { classLoader });
71
    }
72

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

    
77
    public void initialize() {
78
        this.initialize(false);
79
    }
80

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

    
92
    public void postInitialize() {
93
        this.postInitialize(false);
94
    }
95

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

    
107
    public void fullInitialize() {
108
        initialize();
109
        postInitialize();
110
    }
111

    
112
    public void fullInitialize(boolean ignoreerrors) {
113
        initialize(ignoreerrors);
114
        postInitialize(ignoreerrors);
115
    }
116

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

    
123
        return new ArrayList(this.libs);
124
    }
125

    
126
    private void loadLibraries(ClassLoader[] classLoaders, boolean ignoreerrors) {
127
        // Find the available Library instances
128
        Set libs = new HashSet();
129
        LOG.info("Loading libraries of classloaders:");
130
        if (classLoaders == null) {
131
            addLibrariesOfClassLoader(libs, null, ignoreerrors);
132
        } else {
133
            for (int i = 0; i < classLoaders.length; i++) {
134
                addLibrariesOfClassLoader(libs, classLoaders[i], ignoreerrors);
135
            }
136
        }
137

    
138
        int fullSize = libs.size();
139
        this.libs = new OrderedLibs(libs);
140

    
141
        if (LOG.isInfoEnabled()) {
142
            logLibraries(this.libs, fullSize);
143
        }
144
    }
145

    
146
    private void addLibrariesOfClassLoader(Set previousFoundLibs,
147
        ClassLoader classLoader, boolean ignoreerrors) {
148
        StringBuffer logBuf = new StringBuffer();
149
        try {
150
            Set foundLibs = findLibraries(Library.class, classLoader);
151
            foundLibs.removeAll(previousFoundLibs);
152
            logBuf
153
                .append(new Integer(foundLibs.size()))
154
                .append(" new libraries found in the classloader ")
155
                .append(
156
                    classLoader == null ? "DEFAULT" : classLoader.toString())
157
                .append(":");
158

    
159
            for (Iterator iterator = foundLibs.iterator(); iterator.hasNext();) {
160
                Library library = (Library) iterator.next();
161
                try {
162
                    library.doRegistration();
163
                } catch (Throwable e) {
164
                    manageLibraryException(ignoreerrors, "doRegistration",
165
                        library, e);
166
                }
167
                previousFoundLibs.add(library);
168
                logBuf.append("\n- ").append(library);
169
            }
170
            LOG.info(logBuf.toString());
171
        } catch (Exception e) {
172
            String msg =
173
                MessageFormat.format(
174
                    "Error finding libraries of classloader {0}",
175
                    new String[] { classLoader.toString() });
176
            manageLibraryException(ignoreerrors, msg, e);
177
        }
178
    }
179

    
180
    protected abstract Set findLibraries(Class libraryClass,
181
        ClassLoader classLoader);
182

    
183
    private void initializeLibraries(Collection libs, boolean post,
184
        boolean ignoreerrors) {
185
        String label;
186
        if (post) {
187
            label = "postInitialize";
188
        } else {
189
            label = "initialize";
190
        }
191

    
192
        for (Iterator iterator = libs.iterator(); iterator.hasNext();) {
193
            Library lib = (Library) iterator.next();
194
            try {
195
                if (post) {
196
                    LOG.trace("Calling {}.postInitialize()", lib.getClass()
197
                        .getName());
198
                    lib.postInitialize();
199
                } else {
200
                    LOG.trace("Calling {}.initialize()", lib.getClass()
201
                        .getName());
202
                    lib.initialize();
203
                }
204
            } catch (Throwable e) {
205
                manageLibraryException(ignoreerrors, label, lib, e);
206
            }
207
        }
208
    }
209

    
210
    private void manageLibraryException(boolean ignoreerrors, String label,
211
        Library lib, Throwable e) {
212
        String msg;
213
        if (e instanceof BaseRuntimeException) {
214
            msg = ((BaseRuntimeException) e).getLocalizedMessageStack();
215
        } else {
216
            msg = e.getLocalizedMessage();
217
        }
218
        String formattedMsg =
219
            MessageFormat.format("Error in {0} of library {1}. {2}",
220
                new String[] { label, lib.getClass().getName(), msg });
221
        manageLibraryException(ignoreerrors, formattedMsg, e);
222
    }
223

    
224
    private void manageLibraryException(boolean ignoreerrors, String message,
225
        Throwable e) {
226
        if (ignoreerrors) {
227
            LOG.error(message, e);
228
        } else {
229
            if (e instanceof RuntimeException) {
230
                throw (RuntimeException) e;
231
            } else if (e instanceof Error) {
232
                throw (Error) e;
233
            }
234
        }
235
    }
236

    
237
    private void logLibraries(Collection libs, int fullSize) {
238
        StringBuffer buffer = new StringBuffer();
239
        buffer.append("Total libraries to initialize (")
240
            .append(libs == null ? 0 : libs.size()).append(" of ")
241
            .append(fullSize).append("):");
242
        if (libs != null) {
243
            for (Iterator iterator = libs.iterator(); iterator.hasNext();) {
244
                buffer.append("\n- ").append(iterator.next());
245
            }
246
        }
247
        LOG.info(buffer.toString());
248
    }
249

    
250
    private static class OrderedLibs extends ArrayList {
251

    
252
        private static final long serialVersionUID = -8546268624773345053L;
253

    
254
        // By default order alphabetically
255
        private Map apis;
256

    
257
        public OrderedLibs(Set libs) {
258
            apis = new TreeMap(new Comparator() {
259

    
260
                public int compare(Object o1, Object o2) {
261
                    Class class1 = (Class) o1;
262
                    Class class2 = (Class) o2;
263
                    return class1.getName().compareTo(class2.getName());
264
                }
265
            });
266
            orderLibs(libs);
267
        }
268

    
269
        private void orderLibs(Set libs) {
270
            // First create the groups of libraries, internally ordered:
271
            // 1: api, 2: impl, 3: serv1, 4: serv2, ...
272
            // (servs ordered by dependency)
273
            for (Iterator iterator = libs.iterator(); iterator.hasNext();) {
274
                Library library = (Library) iterator.next();
275
                Class API = library.getLibrary();
276
                if (API == null) {
277
                    API = library.getClass();
278
                }
279
                List libraryGroup = (List) apis.get(API);
280
                if (libraryGroup == null) {
281
                    libraryGroup = new LinkedList();
282
                    apis.put(API, libraryGroup);
283
                }
284
                addLibraryToGroup(libraryGroup, library);
285
            }
286

    
287
            Set alreadyAddedGroups = new HashSet();
288
            for (Iterator iterator = apis.keySet().iterator(); iterator
289
                .hasNext();) {
290
                Class APIRequired = (Class) iterator.next();
291
                addFromLibraryGroup(APIRequired, alreadyAddedGroups);
292
            }
293
        }
294

    
295
        private void addLibraryToGroup(List libraryGroup, Library library) {
296
            String type = library.getType();
297

    
298
            // If first, don't look anything else and add it
299
            if (libraryGroup.size() == 0) {
300
                libraryGroup.add(library);
301
                return;
302
            }
303

    
304
            if (API.equals(type)) {
305
                // API library must go first
306
                libraryGroup.add(0, library);
307
            } else if (IMPL.equals(type)) {
308
                // Look for other implementation an replace it if priority
309
                // is higher, or discard
310
                for (int i = 0; i < libraryGroup.size(); i++) {
311
                    Library current = (Library) libraryGroup.get(i);
312
                    if (IMPL.equals(current.getType())) {
313
                        if (current.getPriority() < library.getPriority()) {
314
                            libraryGroup.set(i, library);
315
                            return;
316
                        } else {
317
                            return;
318
                        }
319
                    }
320
                }
321
                // If it is the first implementation, insert it after the API
322
                // and before the services, if any.
323
                Library first = (Library) libraryGroup.get(0);
324
                if (API.equals(first.getType())) {
325
                    if (libraryGroup.size() == 1) {
326
                        libraryGroup.add(library);
327
                    } else {
328
                        libraryGroup.add(1, library);
329
                    }
330
                    return;
331
                } else {
332
                    libraryGroup.add(0, library);
333
                    return;
334
                }
335
            } else { // It is a service type
336

    
337
                // Look for other services and insert by dependency order
338
                for (int i = 0; i < libraryGroup.size(); i++) {
339
                    Library current = (Library) libraryGroup.get(i);
340
                    if (SERVICE.equals(current.getType())) {
341
                        if (current.isRequired(library)) {
342
                            libraryGroup.add(i, library);
343
                            return;
344
                        }
345
                    }
346
                }
347
                // Otherwise add the last
348
                libraryGroup.add(library);
349
            }
350
        }
351

    
352
        private void addFromLibraryGroup(Class APIRequired,
353
            Set alreadyAddedGroups) {
354
            Collection libraryGroup = (Collection) apis.get(APIRequired);
355
            if (libraryGroup != null
356
                && !alreadyAddedGroups.contains(APIRequired)) {
357
                alreadyAddedGroups.add(APIRequired);
358

    
359
                // Add all group libraries, taking into account dependencies
360
                // with other library groups
361
                for (Iterator iterator = libraryGroup.iterator(); iterator
362
                    .hasNext();) {
363
                    Library library = (Library) iterator.next();
364
                    Set requireds = library.getRequireds();
365
                    if (requireds != null) {
366
                        for (Iterator requiredsIter = requireds.iterator(); requiredsIter
367
                            .hasNext();) {
368
                            Required required = (Required) requiredsIter.next();
369
                            addFromLibraryGroup(required.getLibrary(),
370
                                alreadyAddedGroups);
371
                        }
372
                    }
373
                    add(library);
374
                }
375
            }
376
        }
377

    
378
    }
379

    
380
}