blob: c53271b0a76e543cc715ca1f3df89ed2db5014f2 [file] [log] [blame]
/**********************************************************************
* This file is part of "Object Teams Development Tooling"-Software
*
* Copyright 2014 GK Software AG
*
* 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
*
* Please visit http://www.eclipse.org/objectteams for updates and contact.
*
* Contributors:
* Stephan Herrmann - Initial API and implementation
**********************************************************************/
package org.eclipse.objectteams.otequinox.turbo;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Dictionary;
import org.eclipse.osgi.framework.log.FrameworkLog;
import org.eclipse.osgi.framework.log.FrameworkLogEntry;
import org.eclipse.osgi.framework.util.Headers;
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.storage.BundleInfo.Generation;
import org.osgi.framework.BundleException;
import org.osgi.framework.Constants;
/** This class intercepts each bundle manifest and checks if forced exports must be injected. */
public class OTStorageHook extends StorageHookFactory<Object, Object, OTStorageHook.StorageHookImpl> implements HookConfigurator {
// HINTS FOR DEBUGGING:
// - This fragment must be colocated with org.eclipse.osgi - perhaps a symbolic link helps to establish this.
// - This class must be accessible by its qualified name with no leading "src", again a symbolic link my help:
// $ ln -s bin/org org
private FrameworkLog fwLog;
class StorageHookImpl extends StorageHookFactory.StorageHook<Object,Object> {
public StorageHookImpl(Generation generation) {
super(generation, OTStorageHook.class);
}
@Override
public void initialize(Dictionary<String, String> manifest) throws BundleException {
// when initializing, intercept the manifest and conditionally inject forced exports
String[] id = manifest.get(Constants.BUNDLE_SYMBOLICNAME).split(";");
if (id.length > 0) {
String packages = ForcedExportsRegistry.getGrantedForcedExportsByBase(id[0]);
if (packages != null && !packages.isEmpty()) {
String exportedPackages = manifest.get(Constants.EXPORT_PACKAGE);
if (exportedPackages != null && !exportedPackages.isEmpty())
exportedPackages = exportedPackages+','+packages;
else
exportedPackages = packages;
putHeader(id[0], Constants.EXPORT_PACKAGE, exportedPackages, packages);
}
}
}
/** Reflexively perform our (unusual) work. */
void putHeader(String id, String header, String value, String added) {
try {
Generation gen = getGeneration();
Method getRawHeaders = gen.getClass().getDeclaredMethod("getRawHeaders", new Class<?>[0]);
getRawHeaders.setAccessible(true);
@SuppressWarnings("unchecked")
Headers<String,String> headers = (Headers<String, String>) getRawHeaders.invoke(gen, new Object[0]);
Field readOnly = headers.getClass().getDeclaredField("readOnly");
readOnly.setAccessible(true);
readOnly.set(headers, false);
// pay-load:
headers.put(header, value);
// restore:
readOnly.setAccessible(false);
getRawHeaders.setAccessible(false);
fwLog.log(new FrameworkLogEntry(OTStorageHook.class.getName(), "OT/Equinox Turbo: added forced export into base bundle "+id+":\n\t"+added, FrameworkLogEntry.INFO, null, null));
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchFieldException e) {
fwLog.log(new FrameworkLogEntry(OTStorageHook.class.getName(), "Unable to inject forced exports", FrameworkLogEntry.ERROR, e, null));
}
}
@Override
public void load(Object loadContext, DataInputStream is) throws IOException {
// nop
}
@Override
public void save(Object saveContext, DataOutputStream os) throws IOException {
// nop
}
}
@Override
public void addHooks(HookRegistry hookRegistry) {
hookRegistry.addStorageHookFactory(this);
fwLog = hookRegistry.getContainer().getLogServices().getFrameworkLog();
ForcedExportsRegistry.install(fwLog);
}
@Override
protected StorageHookImpl createStorageHook(Generation generation) {
return new StorageHookImpl(generation);
}
@Override
public int getStorageVersion() {
return 0;
}
@Override
public boolean isCompatibleWith(int version) {
return false; // FIXME: forcing to re-init every time, is this OK?
}
}