/******************************************************************************* * Copyright (c) 2011 Gerd Wuetherich (gerd@gerd-wuetherich.de). * 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: * Gerd Wuetherich (gerd@gerd-wuetherich.de) - initial API and implementation ******************************************************************************/ package org.bundlemaker.core.osgi.exporter; import java.util.ArrayList; import java.util.Collections; import java.util.Dictionary; import java.util.HashSet; import java.util.Hashtable; import java.util.List; import java.util.Properties; import java.util.Set; import org.bundlemaker.core.common.IResource; import org.bundlemaker.core.common.collections.GenericCache; import org.bundlemaker.core.exporter.AbstractExporter; import org.bundlemaker.core.exporter.IModuleExporterContext; import org.bundlemaker.core.exporter.ITemplateProvider; import org.bundlemaker.core.osgi.internal.exporter.ManifestCreatorAdapter; import org.bundlemaker.core.osgi.manifest.DefaultManifestCreator; import org.bundlemaker.core.osgi.manifest.DefaultManifestPreferences; import org.bundlemaker.core.osgi.manifest.IBundleManifestCreator; import org.bundlemaker.core.osgi.manifest.IManifestPreferences; import org.bundlemaker.core.osgi.utils.ManifestUtils; import org.bundlemaker.core.resource.IModularizedSystem; import org.bundlemaker.core.resource.IModule; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.osgi.service.resolver.StateObjectFactory; import org.eclipse.virgo.util.parser.manifest.ManifestContents; import org.osgi.framework.BundleException; /** * <p> * Abstract base class for all OSGi manifest aware exporter. * </p> * * @author Gerd Wütherich (gerd@gerd-wuetherich.de) */ public abstract class AbstractManifestAwareExporter extends AbstractExporter { /** the current manifest contents */ private ManifestContents _manifestContents; /** the bundle manifest creator */ private IBundleManifestCreator _creator; /** the template provider */ private ITemplateProvider _templateProvider; /** the manifest preferences */ private IManifestPreferences _manifestPreferences; /** the list of interceptors */ private List<IManifestContentsInterceptor> _interceptors; /** the internal manifest cache */ private CycleAwareGenericCache _manifestCache; /** * <p> * Creates a new instance of type {@link AbstractManifestAwareExporter}. * </p> * * @param templateProvider * @param bundleManifestCreator * @param manifestPreferences */ protected AbstractManifestAwareExporter(ITemplateProvider templateProvider, IBundleManifestCreator bundleManifestCreator, IManifestPreferences manifestPreferences) { // null-safe initialize _templateProvider = templateProvider != null ? templateProvider : new NullTemplateProvider(); _creator = bundleManifestCreator != null ? bundleManifestCreator : new DefaultManifestCreator(); _manifestPreferences = manifestPreferences != null ? manifestPreferences : new DefaultManifestPreferences(false); // _manifestCache = new CycleAwareGenericCache(); _interceptors = new ArrayList<IManifestContentsInterceptor>(); } /** * <p> * Returns the {@link ITemplateProvider} for this exporter. * </p> * * @return the {@link ITemplateProvider} for this exporter. */ public final ITemplateProvider getTemplateProvider() { return _templateProvider; } /** * <p> * Returns the list of interceptors. * </p> * * @return the list of interceptors. */ public final List<IManifestContentsInterceptor> getInterceptors() { return _interceptors; } /** * <p> * Sets the manifest preferences. * </p> * * @param manifestPreferences * the manifest preferences. */ public void setManifestPreferences(IManifestPreferences manifestPreferences) { Assert.isNotNull(manifestPreferences); _manifestPreferences = manifestPreferences; } /** * <p> * Returns the current manifest contents. * </p> * * @return the current manifest contents. */ public ManifestContents getManifestContents() { return _manifestContents; } /** * {@inheritDoc} */ @Override protected void preExportModule() throws CoreException { // call super super.preExportModule(); // get the manifest contents _manifestCache.clearCycleSet(); _manifestContents = _manifestCache.getOrCreate(getCurrentModule()); // check the manifest Dictionary<String, String> dictionary = null; try { dictionary = new Hashtable<String, String>(); Properties properties = ManifestUtils.convertManifest(ManifestUtils.toManifest(_manifestContents)); for (String propertyName : properties.stringPropertyNames()) { dictionary.put(propertyName, properties.getProperty(propertyName)); } StateObjectFactory.defaultFactory.createBundleDescription(null, dictionary, "internal", 1); } catch (BundleException e) { // TODO System.out.println(dictionary); e.printStackTrace(); throw new CoreException(new Status(IStatus.ERROR, "", "")); } } /** * <p> * Executes all registered interceptors for the given manifest contents * </p> * * @param manifestContents * the manifest contents * @param modularizedSystem * the {@link IModularizedSystem} * @param module * the {@link IModule} */ private final void executeInterceptors(ManifestContents manifestContents, IModularizedSystem modularizedSystem, IModule module) { // iterate over all the interceptors for (IManifestContentsInterceptor interceptor : _interceptors) { // assert not null if (interceptor != null) { // call manipulateManifestContents interceptor.manipulateManifestContents(manifestContents, modularizedSystem, module); } } } /** * <p> * Cache that creates manifests for a given resource module. If the module is a fragment module, the host module will * be resolved first as the host manifest is needed to create the fragment manifest. * </p> * * @author Gerd Wütherich (gerd@gerd-wuetherich.de) */ private final class CycleAwareGenericCache extends GenericCache<IModule, ManifestContents> { /** default serialVersionUID */ private static final long serialVersionUID = 1L; /** the host modules */ private Set<IModule> _hostModules = new HashSet<IModule>(); /** * {@inheritDoc} */ @Override protected ManifestContents create(IModule resourceModule) { // define the host manifest contents (as it is needed to create a fragments manifest correctly) ManifestContents hostManifestContents = null; // test if the resource module is a fragment if (ManifestUtils.isFragment(resourceModule)) { // find the host module IModule hostModule = (IModule) ManifestUtils.getFragmentHost(resourceModule); // check (should not be false here) if (!hostModule.equals(resourceModule)) { // check if the module has already been handled to prevent loops if (_hostModules.contains(hostModule)) { // throw RuntimeException throw new RuntimeException("CycleException " + _hostModules); } else { // add to handled modules list _hostModules.add(hostModule); // get the host manifest contents hostManifestContents = this.getOrCreate(hostModule); } } } // create the adapter ManifestCreatorAdapter adapter = new ManifestCreatorAdapter(getCurrentModularizedSystem(), resourceModule, getCurrentContext(), _templateProvider, hostManifestContents, _creator, _manifestPreferences); // create the manifest contents ManifestContents manifestContents = adapter.createManifest(); // Assert.isNotNull(manifestContents, String.format("The method createManifest() of class '%s' returned 'null'.", adapter.getClass().getName())); // execute the interceptors executeInterceptors(manifestContents, getCurrentModularizedSystem(), resourceModule); // return the manifest contents return manifestContents; } /** * <p> * Clears the cycle set. * </p> */ public void clearCycleSet() { _hostModules.clear(); } } /** * <p> * Default implementation of an {@link ITemplateProvider} that returns no templates. * </p> * * @author Gerd Wütherich (gerd@gerd-wuetherich.de) */ class NullTemplateProvider implements ITemplateProvider { /** * {@inheritDoc} */ @Override public ManifestContents getTemplate(IModule module, IModularizedSystem modularizedSystem, IModuleExporterContext context) { return null; } /** * {@inheritDoc} */ @Override public Set<IResource> getAdditionalResources(IModule currentModule, IModularizedSystem currentModularizedSystem, IModuleExporterContext currentContext) { // return Collections.emptySet(); } } }