All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.osgi.internal.connect.ConnectHookConfigurator Maven / Gradle / Ivy

There is a newer version: 1.9.3.RC1
Show newest version
/*******************************************************************************
 * Copyright (c) 2019, 2021 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.osgi.internal.connect;

import static org.eclipse.osgi.internal.framework.EquinoxContainer.sneakyThrow;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.eclipse.osgi.container.Module;
import org.eclipse.osgi.container.ModuleContainerAdaptor.ModuleEvent;
import org.eclipse.osgi.container.ModuleRevisionBuilder;
import org.eclipse.osgi.internal.framework.EquinoxConfiguration;
import org.eclipse.osgi.internal.framework.EquinoxContainer.ConnectModules;
import org.eclipse.osgi.internal.hookregistry.ClassLoaderHook;
import org.eclipse.osgi.internal.hookregistry.HookConfigurator;
import org.eclipse.osgi.internal.hookregistry.HookRegistry;
import org.eclipse.osgi.internal.hookregistry.StorageHookFactory;
import org.eclipse.osgi.internal.hookregistry.StorageHookFactory.StorageHook;
import org.eclipse.osgi.internal.loader.BundleLoader;
import org.eclipse.osgi.internal.loader.ModuleClassLoader;
import org.eclipse.osgi.storage.BundleInfo.Generation;
import org.eclipse.osgi.storage.bundlefile.BundleFile;
import org.eclipse.osgi.storage.bundlefile.BundleFileWrapperChain;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.framework.connect.ConnectContent;
import org.osgi.framework.connect.ConnectModule;
import org.osgi.framework.connect.ModuleConnector;
import org.osgi.framework.namespace.BundleNamespace;
import org.osgi.framework.namespace.HostNamespace;
import org.osgi.framework.namespace.IdentityNamespace;

public class ConnectHookConfigurator implements HookConfigurator {
	static final Collection CONNECT_TAG_NAMESPACES = new ArrayList<>(Arrays.asList(
			BundleNamespace.BUNDLE_NAMESPACE, HostNamespace.HOST_NAMESPACE, IdentityNamespace.IDENTITY_NAMESPACE));

	@Override
	public void addHooks(final HookRegistry hookRegistry) {
		final ConnectModules connectModules = hookRegistry.getContainer().getConnectModules();
		ModuleConnector moduleConnector = connectModules.getModuleConnector();

		hookRegistry.addStorageHookFactory(new StorageHookFactory>() {
			@Override
			protected StorageHook createStorageHook(Generation generation) {
				final ConnectModule m = connectModules.getConnectModule(generation.getBundleInfo().getLocation());

				return new StorageHook(generation, this.getClass()) {
					boolean hasModule = false;

					@Override
					public void save(Object saveContext, DataOutputStream os) throws IOException {
						os.writeBoolean(m != null);
					}

					@Override
					public void load(Object loadContext, DataInputStream is) throws IOException {
						hasModule = is.readBoolean();
					}

					@Override
					public void validate() throws IllegalStateException {
						// make sure we have the module still from the factory
						if (hasModule && m == null) {
							throw new IllegalStateException("Connect Factory no longer has the module at locataion: " //$NON-NLS-1$
									+ generation.getBundleInfo().getLocation());
						}
					}

					@Override
					public ModuleRevisionBuilder adaptModuleRevisionBuilder(ModuleEvent operation, Module origin,
							ModuleRevisionBuilder builder) {
						if (m != null) {
							CONNECT_TAG_NAMESPACES.stream().map(builder::getCapabilities).flatMap(List::stream)
									.forEach(c -> c.getAttributes().compute(IdentityNamespace.CAPABILITY_TAGS_ATTRIBUTE,
											(k, v) -> {
												if (v == null) {
													return Collections.singletonList(ConnectContent.TAG_OSGI_CONNECT);
												}
												if (v instanceof List) {
													@SuppressWarnings({ "unchecked", "rawtypes" })
													List l = new ArrayList<>((List) v);
													l.add(ConnectContent.TAG_OSGI_CONNECT);
													return Collections.unmodifiableList(l);
												}
												// should not get here, but just recover
												return Arrays.asList(v, ConnectContent.TAG_OSGI_CONNECT);
											}));
							return builder;
						}
						return null;
					}
				};
			}

			@Override
			public URLConnection handleContentConnection(Module module, String location, InputStream in) {
				if (in != null) {
					// Do not call ModuleConnector method connect when input stream is non null.
					return null;
				}
				if (location == null) {
					location = module.getLocation();
				}
				try {
					ConnectModule m = connectModules.connect(location);
					if (m != null) {
						return ConnectInputStream.URL_CONNECTION_INSTANCE;
					}
				} catch (IllegalStateException e) {
					if (e.getCause() instanceof BundleException) {
						sneakyThrow(e.getCause());
					}
				}
				return null;
			}
		});

		if (moduleConnector == null) {
			return;
		}

		hookRegistry.addClassLoaderHook(new ClassLoaderHook() {
			@Override
			public ModuleClassLoader createClassLoader(ClassLoader parent, EquinoxConfiguration configuration,
					BundleLoader delegate, Generation generation) {
				ConnectModule m = connectModules.getConnectModule(generation.getBundleInfo().getLocation());
				if (m != null) {
					BundleFile bundlefile = generation.getBundleFile();
					if (bundlefile instanceof BundleFileWrapperChain) {
						BundleFileWrapperChain chain = (BundleFileWrapperChain) bundlefile;
						while (chain.getNext() != null) {
							chain = chain.getNext();
						}
						bundlefile = chain.getBundleFile();
					}
					if (bundlefile instanceof ConnectBundleFile) {
						return ((ConnectBundleFile) bundlefile).getClassLoader().map(
								l -> new DelegatingConnectClassLoader(parent, configuration, delegate, generation, l))
								.orElse(null);
					}
				}
				return null;
			}
		});

		hookRegistry.addActivatorHookFactory(() -> {
			final List activators = new ArrayList<>();
			moduleConnector.newBundleActivator().ifPresent(activators::add);
			return new BundleActivator() {
				@Override
				public void start(BundleContext context) throws Exception {
					for (BundleActivator activator : activators) {
						activator.start(context);
					}
				}

				@Override
				public void stop(BundleContext context) throws Exception {
					for (BundleActivator activator : activators) {
						activator.stop(context);
					}
				}
			};
		});
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy