File: HookRegistry.java

package info (click to toggle)
libequinox-osgi-java 3.9.1-6
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 5,068 kB
  • sloc: java: 57,768; makefile: 9
file content (334 lines) | stat: -rw-r--r-- 14,125 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
/*******************************************************************************
 * Copyright (c) 2005, 2010 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/

package org.eclipse.osgi.baseadaptor;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.*;
import org.eclipse.osgi.baseadaptor.hooks.*;
import org.eclipse.osgi.framework.adaptor.*;
import org.eclipse.osgi.framework.internal.core.FrameworkProperties;
import org.eclipse.osgi.framework.log.FrameworkLogEntry;
import org.eclipse.osgi.util.ManifestElement;

/**
 * The hook registry is used to store all the hooks which are
 * configured by the hook configurators.
 * @see HookConfigurator
 * @since 3.2
 */
public final class HookRegistry {
	/**
	 * The hook configurators properties file (&quot;hookconfigurators.properties&quot;) <p>
	 * A framework extension may supply a hook configurators properties file to specify a 
	 * list of hook configurators.
	 * @see #HOOK_CONFIGURATORS
	 */
	public static final String HOOK_CONFIGURATORS_FILE = "hookconfigurators.properties"; //$NON-NLS-1$

	/**
	 * The hook configurators property key (&quot;hookconfigurators.properties&quot;) used in 
	 * a hook configurators properties file to specify a comma separated list of fully 
	 * qualified hook configurator classes.
	 */
	public static final String HOOK_CONFIGURATORS = "hook.configurators"; //$NON-NLS-1$

	/**
	 * A system property (&quot;osgi.hook.configurators.include&quot;) used to add additional
	 * hook configurators.  This is helpful for configuring optional hook configurators.
	 */
	public static final String PROP_HOOK_CONFIGURATORS_INCLUDE = "osgi.hook.configurators.include"; //$NON-NLS-1$

	/**
	 * A system property (&quot;osgi.hook.configurators.exclude&quot;) used to exclude 
	 * any hook configurators.  This is helpful for disabling hook
	 * configurators that is specified in hook configurator properties files.
	 */
	public static final String PROP_HOOK_CONFIGURATORS_EXCLUDE = "osgi.hook.configurators.exclude"; //$NON-NLS-1$

	/**
	 * A system property (&quot;osgi.hook.configurators&quot;) used to specify the list
	 * of hook configurators.  If this property is set then the list of configurators 
	 * specified will be the only configurators used.
	 */
	public static final String PROP_HOOK_CONFIGURATORS = "osgi.hook.configurators"; //$NON-NLS-1$

	private static final String BUILTIN_HOOKS = "builtin.hooks"; //$NON-NLS-1$

	private BaseAdaptor adaptor;
	private boolean readonly = false;
	private AdaptorHook[] adaptorHooks = new AdaptorHook[0];
	private BundleWatcher[] watchers = new BundleWatcher[0];
	private ClassLoadingHook[] classLoadingHooks = new ClassLoadingHook[0];
	private ClassLoadingStatsHook[] classLoadingStatsHooks = new ClassLoadingStatsHook[0];
	private ClassLoaderDelegateHook[] classLoaderDelegateHooks = new ClassLoaderDelegateHook[0];
	private StorageHook[] storageHooks = new StorageHook[0];
	private BundleFileFactoryHook[] bundleFileFactoryHooks = new BundleFileFactoryHook[0];
	private BundleFileWrapperFactoryHook[] bundleFileWrapperFactoryHooks = new BundleFileWrapperFactoryHook[0];

	public HookRegistry(BaseAdaptor adaptor) {
		this.adaptor = adaptor;
	}

	/**
	 * Initializes the hook configurators.  The following steps are used to initialize the hook configurators. <p>
	 * 1. Get a list of hook configurators from all hook configurators properties files on the classpath, 
	 *    add this list to the overall list of hook configurators, remove duplicates. <p>
	 * 2. Get a list of hook configurators from the (&quot;osgi.hook.configurators.include&quot;) system property 
	 *    and add this list to the overall list of hook configurators, remove duplicates. <p>
	 * 3. Get a list of hook configurators from the (&quot;osgi.hook.configurators.exclude&quot;) system property
	 *    and remove this list from the overall list of hook configurators. <p>
	 * 4. Load each hook configurator class, create a new instance, then call the {@link HookConfigurator#addHooks(HookRegistry)} method <p>
	 * 5. Set this HookRegistry object to read only to prevent any other hooks from being added. <p>
	 * @return an array of error log entries that occurred while initializing the hooks
	 */
	public FrameworkLogEntry[] initialize() {
		List<String> configurators = new ArrayList<String>(5);
		List<FrameworkLogEntry> errors = new ArrayList<FrameworkLogEntry>(0); // optimistic that no errors will occur
		mergeFileHookConfigurators(configurators, errors);
		mergePropertyHookConfigurators(configurators);
		loadConfigurators(configurators, errors);
		// set to read-only
		readonly = true;
		return errors.toArray(new FrameworkLogEntry[errors.size()]);
	}

	private void mergeFileHookConfigurators(List<String> configuratorList, List<FrameworkLogEntry> errors) {
		ClassLoader cl = getClass().getClassLoader();
		// get all hook configurators files in your classloader delegation
		Enumeration<URL> hookConfigurators;
		try {
			hookConfigurators = cl != null ? cl.getResources(HookRegistry.HOOK_CONFIGURATORS_FILE) : ClassLoader.getSystemResources(HookRegistry.HOOK_CONFIGURATORS_FILE);
		} catch (IOException e) {
			errors.add(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, "getResources error on " + HookRegistry.HOOK_CONFIGURATORS_FILE, 0, e, null)); //$NON-NLS-1$
			return;
		}
		int curBuiltin = 0;
		while (hookConfigurators.hasMoreElements()) {
			URL url = hookConfigurators.nextElement();
			InputStream input = null;
			try {
				// check each file for a hook.configurators property
				Properties configuratorProps = new Properties();
				input = url.openStream();
				configuratorProps.load(input);
				String hooksValue = configuratorProps.getProperty(HOOK_CONFIGURATORS);
				if (hooksValue == null)
					continue;
				boolean builtin = Boolean.valueOf(configuratorProps.getProperty(BUILTIN_HOOKS)).booleanValue();
				String[] configurators = ManifestElement.getArrayFromList(hooksValue, ","); //$NON-NLS-1$
				for (int i = 0; i < configurators.length; i++)
					if (!configuratorList.contains(configurators[i])) {
						if (builtin) // make sure the built-in configurators are listed first (bug 170881)
							configuratorList.add(curBuiltin++, configurators[i]);
						else
							configuratorList.add(configurators[i]);
					}
			} catch (IOException e) {
				errors.add(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, "error loading: " + url.toExternalForm(), 0, e, null)); //$NON-NLS-1$
				// ignore and continue to next URL
			} finally {
				if (input != null)
					try {
						input.close();
					} catch (IOException e) {
						// do nothing
					}
			}
		}
	}

	private void mergePropertyHookConfigurators(List<String> configuratorList) {
		// see if there is a configurators list
		String[] configurators = ManifestElement.getArrayFromList(FrameworkProperties.getProperty(HookRegistry.PROP_HOOK_CONFIGURATORS), ","); //$NON-NLS-1$
		if (configurators.length > 0) {
			configuratorList.clear(); // clear the list, we are only going to use the configurators from the list
			for (int i = 0; i < configurators.length; i++)
				if (!configuratorList.contains(configurators[i]))
					configuratorList.add(configurators[i]);
			return; // don't do anything else
		}
		// Make sure the configurators from the include property are in the list
		String[] includeConfigurators = ManifestElement.getArrayFromList(FrameworkProperties.getProperty(HookRegistry.PROP_HOOK_CONFIGURATORS_INCLUDE), ","); //$NON-NLS-1$
		for (int i = 0; i < includeConfigurators.length; i++)
			if (!configuratorList.contains(includeConfigurators[i]))
				configuratorList.add(includeConfigurators[i]);
		// Make sure the configurators from the exclude property are no in the list
		String[] excludeHooks = ManifestElement.getArrayFromList(FrameworkProperties.getProperty(HookRegistry.PROP_HOOK_CONFIGURATORS_EXCLUDE), ","); //$NON-NLS-1$
		for (int i = 0; i < excludeHooks.length; i++)
			configuratorList.remove(excludeHooks[i]);
	}

	private void loadConfigurators(List<String> configurators, List<FrameworkLogEntry> errors) {
		for (Iterator<String> iHooks = configurators.iterator(); iHooks.hasNext();) {
			String hookName = iHooks.next();
			try {
				Class<?> clazz = Class.forName(hookName);
				HookConfigurator configurator = (HookConfigurator) clazz.newInstance();
				configurator.addHooks(this);
			} catch (Throwable t) {
				// We expect the follow exeptions may happen; but we need to catch all here
				// ClassNotFoundException
				// IllegalAccessException
				// InstantiationException
				// ClassCastException
				errors.add(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, "error loading hook: " + hookName, 0, t, null)); //$NON-NLS-1$
			}
		}
	}

	/**
	 * Returns the list of configured adaptor hooks.
	 * @return the list of configured adaptor hooks.
	 */
	public AdaptorHook[] getAdaptorHooks() {
		return adaptorHooks;
	}

	/**
	 * Returns the list of configured bundle watchers.
	 * @return the list of configured bundle watchers.
	 */
	public BundleWatcher[] getWatchers() {
		return watchers;
	}

	/**
	 * Returns the list of configured class loading hooks.
	 * @return the list of configured class loading hooks.
	 */
	public ClassLoadingHook[] getClassLoadingHooks() {
		return classLoadingHooks;
	}

	/**
	 * Returns the list of configured class loading stats hooks.
	 * @return the list of configured class loading stats hooks.
	 */
	public ClassLoadingStatsHook[] getClassLoadingStatsHooks() {
		return classLoadingStatsHooks;
	}

	/**
	 * Returns the list of configured class loader delegate hooks.
	 * @return the list of configured class loader delegate hooks.
	 */
	public ClassLoaderDelegateHook[] getClassLoaderDelegateHooks() {
		return classLoaderDelegateHooks;
	}

	/**
	 * Returns the list of configured storage hooks.
	 * @return the list of configured storage hooks.
	 */
	public StorageHook[] getStorageHooks() {
		return storageHooks;
	}

	/**
	 * Returns the list of configured bundle file factories.
	 * @return the list of configured bundle file factories.
	 */
	public BundleFileFactoryHook[] getBundleFileFactoryHooks() {
		return bundleFileFactoryHooks;
	}

	/**
	 * Returns the configured bundle file wrapper factories
	 * @return the configured bundle file wrapper factories
	 */
	public BundleFileWrapperFactoryHook[] getBundleFileWrapperFactoryHooks() {
		return bundleFileWrapperFactoryHooks;
	}

	/**
	 * Adds a adaptor hook to this hook registry.
	 * @param adaptorHook an adaptor hook object.
	 */
	public void addAdaptorHook(AdaptorHook adaptorHook) {
		adaptorHooks = (AdaptorHook[]) add(adaptorHook, adaptorHooks, new AdaptorHook[adaptorHooks.length + 1]);
	}

	/**
	 * Adds a bundle watcher to this hook registry.
	 * @param watcher a bundle watcher object.
	 */
	public void addWatcher(BundleWatcher watcher) {
		watchers = (BundleWatcher[]) add(watcher, watchers, new BundleWatcher[watchers.length + 1]);
	}

	/**
	 * Adds a class loading hook to this hook registry.
	 * @param classLoadingHook a class loading hook object.
	 */
	public void addClassLoadingHook(ClassLoadingHook classLoadingHook) {
		classLoadingHooks = (ClassLoadingHook[]) add(classLoadingHook, classLoadingHooks, new ClassLoadingHook[classLoadingHooks.length + 1]);
	}

	/**
	 * Adds a class loading stats hook to this hook registry.
	 * @param classLoadingStatsHook a class loading hook object.
	 */
	public void addClassLoadingStatsHook(ClassLoadingStatsHook classLoadingStatsHook) {
		classLoadingStatsHooks = (ClassLoadingStatsHook[]) add(classLoadingStatsHook, classLoadingStatsHooks, new ClassLoadingStatsHook[classLoadingStatsHooks.length + 1]);
	}

	/**
	 * Adds a class loader delegate hook to this hook registry.
	 * @param classLoaderDelegateHook a class loader delegate hook.
	 */
	public void addClassLoaderDelegateHook(ClassLoaderDelegateHook classLoaderDelegateHook) {
		classLoaderDelegateHooks = (ClassLoaderDelegateHook[]) add(classLoaderDelegateHook, classLoaderDelegateHooks, new ClassLoaderDelegateHook[classLoaderDelegateHooks.length + 1]);
	}

	/**
	 * Adds a storage hook to this hook registry.
	 * @param storageHook a storage hook object.
	 */
	public void addStorageHook(StorageHook storageHook) {
		storageHooks = (StorageHook[]) add(storageHook, storageHooks, new StorageHook[storageHooks.length + 1]);
	}

	/**
	 * Adds a bundle file factory to this hook registry.
	 * @param factory a bundle file factory object.
	 */
	public void addBundleFileFactoryHook(BundleFileFactoryHook factory) {
		bundleFileFactoryHooks = (BundleFileFactoryHook[]) add(factory, bundleFileFactoryHooks, new BundleFileFactoryHook[bundleFileFactoryHooks.length + 1]);
	}

	/**
	 * Adds a bundle file wrapper factory for this hook registry
	 * @param factory a bundle file wrapper factory object.
	 */
	public void addBundleFileWrapperFactoryHook(BundleFileWrapperFactoryHook factory) {
		bundleFileWrapperFactoryHooks = (BundleFileWrapperFactoryHook[]) add(factory, bundleFileWrapperFactoryHooks, new BundleFileWrapperFactoryHook[bundleFileWrapperFactoryHooks.length + 1]);
	}

	private Object[] add(Object newValue, Object[] oldValues, Object[] newValues) {
		if (readonly)
			throw new IllegalStateException("Cannot add hooks dynamically."); //$NON-NLS-1$
		if (oldValues.length > 0)
			System.arraycopy(oldValues, 0, newValues, 0, oldValues.length);
		newValues[oldValues.length] = newValue;
		return newValues;
	}

	/**
	 * Returns the base adaptor associated with this hook registry.
	 * @return the base adaptor associated with this hook registry.
	 */
	public BaseAdaptor getAdaptor() {
		return adaptor;
	}
}