| /******************************************************************************* |
| * Copyright (c) 2005, 2008 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.core.runtime.internal.adaptor; |
| |
| import java.io.File; |
| import java.security.ProtectionDomain; |
| import java.util.ArrayList; |
| import java.util.jar.Attributes; |
| import java.util.jar.Manifest; |
| import org.eclipse.osgi.baseadaptor.*; |
| import org.eclipse.osgi.baseadaptor.bundlefile.BundleEntry; |
| import org.eclipse.osgi.baseadaptor.bundlefile.BundleFile; |
| import org.eclipse.osgi.baseadaptor.hooks.ClassLoadingHook; |
| import org.eclipse.osgi.baseadaptor.loader.*; |
| import org.eclipse.osgi.framework.adaptor.BundleProtectionDomain; |
| import org.eclipse.osgi.framework.adaptor.ClassLoaderDelegate; |
| import org.eclipse.osgi.internal.baseadaptor.BaseClassLoadingHook; |
| import org.eclipse.osgi.internal.baseadaptor.BaseStorageHook; |
| |
| public class EclipseClassLoadingHook implements ClassLoadingHook, HookConfigurator { |
| private static String[] NL_JAR_VARIANTS = buildNLJarVariants(EclipseEnvironmentInfo.getDefault().getNL()); |
| private static boolean DEFINE_PACKAGES; |
| private static String[] LIB_VARIANTS = buildLibraryVariants(); |
| private Object pkgLock = new Object(); |
| |
| static { |
| try { |
| Class.forName("java.lang.Package"); //$NON-NLS-1$ |
| DEFINE_PACKAGES = true; |
| } catch (ClassNotFoundException e) { |
| DEFINE_PACKAGES = false; |
| } |
| } |
| |
| private static String[] buildLibraryVariants() { |
| ArrayList result = new ArrayList(); |
| EclipseEnvironmentInfo info = EclipseEnvironmentInfo.getDefault(); |
| result.add("ws/" + info.getWS() + "/"); //$NON-NLS-1$ //$NON-NLS-2$ |
| result.add("os/" + info.getOS() + "/" + info.getOSArch() + "/"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| result.add("os/" + info.getOS() + "/"); //$NON-NLS-1$ //$NON-NLS-2$ |
| String nl = info.getNL(); |
| nl = nl.replace('_', '/'); |
| while (nl.length() > 0) { |
| result.add("nl/" + nl + "/"); //$NON-NLS-1$ //$NON-NLS-2$ |
| int i = nl.lastIndexOf('/'); |
| nl = (i < 0) ? "" : nl.substring(0, i); //$NON-NLS-1$ |
| } |
| result.add(""); //$NON-NLS-1$ |
| return (String[]) result.toArray(new String[result.size()]); |
| } |
| |
| public byte[] processClass(String name, byte[] classbytes, ClasspathEntry classpathEntry, BundleEntry entry, ClasspathManager manager) { |
| if (!DEFINE_PACKAGES) |
| return null; |
| // Define the package if it is not the default package. |
| int lastIndex = name.lastIndexOf('.'); |
| if (lastIndex < 0) |
| return null; |
| String packageName = name.substring(0, lastIndex); |
| Object pkg; |
| synchronized (pkgLock) { |
| pkg = manager.getBaseClassLoader().publicGetPackage(packageName); |
| if (pkg != null) |
| return null; |
| } |
| |
| // get info about the package from the classpath entry's manifest. |
| String specTitle = null, specVersion = null, specVendor = null, implTitle = null, implVersion = null, implVendor = null; |
| ClasspathManifest cpm = (ClasspathManifest) classpathEntry.getUserObject(ClasspathManifest.KEY); |
| if (cpm == null) { |
| cpm = new ClasspathManifest(); |
| classpathEntry.addUserObject(cpm); |
| } |
| Manifest mf = cpm.getManifest(classpathEntry, manager); |
| if (mf != null) { |
| Attributes mainAttributes = mf.getMainAttributes(); |
| String dirName = packageName.replace('.', '/') + '/'; |
| Attributes packageAttributes = mf.getAttributes(dirName); |
| boolean noEntry = false; |
| if (packageAttributes == null) { |
| noEntry = true; |
| packageAttributes = mainAttributes; |
| } |
| specTitle = packageAttributes.getValue(Attributes.Name.SPECIFICATION_TITLE); |
| if (specTitle == null && !noEntry) |
| specTitle = mainAttributes.getValue(Attributes.Name.SPECIFICATION_TITLE); |
| specVersion = packageAttributes.getValue(Attributes.Name.SPECIFICATION_VERSION); |
| if (specVersion == null && !noEntry) |
| specVersion = mainAttributes.getValue(Attributes.Name.SPECIFICATION_VERSION); |
| specVendor = packageAttributes.getValue(Attributes.Name.SPECIFICATION_VENDOR); |
| if (specVendor == null && !noEntry) |
| specVendor = mainAttributes.getValue(Attributes.Name.SPECIFICATION_VENDOR); |
| implTitle = packageAttributes.getValue(Attributes.Name.IMPLEMENTATION_TITLE); |
| if (implTitle == null && !noEntry) |
| implTitle = mainAttributes.getValue(Attributes.Name.IMPLEMENTATION_TITLE); |
| implVersion = packageAttributes.getValue(Attributes.Name.IMPLEMENTATION_VERSION); |
| if (implVersion == null && !noEntry) |
| implVersion = mainAttributes.getValue(Attributes.Name.IMPLEMENTATION_VERSION); |
| implVendor = packageAttributes.getValue(Attributes.Name.IMPLEMENTATION_VENDOR); |
| if (implVendor == null && !noEntry) |
| implVendor = mainAttributes.getValue(Attributes.Name.IMPLEMENTATION_VENDOR); |
| } |
| // The package is not defined yet define it before we define the class. |
| // TODO still need to seal packages. |
| synchronized (pkgLock) { |
| pkg = manager.getBaseClassLoader().publicGetPackage(packageName); |
| if (pkg != null) |
| return null; |
| manager.getBaseClassLoader().publicDefinePackage(packageName, specTitle, specVersion, specVendor, implTitle, implVersion, implVendor, null); |
| } |
| // not doing any byte processing |
| return null; |
| } |
| |
| public boolean addClassPathEntry(ArrayList cpEntries, String cp, ClasspathManager hostmanager, BaseData sourcedata, ProtectionDomain sourcedomain) { |
| String var = hasPrefix(cp); |
| if (var != null) |
| // find internal library using eclipse predefined vars |
| return addInternalClassPath(var, cpEntries, cp, hostmanager, sourcedata, sourcedomain); |
| if (cp.startsWith(BaseStorageHook.EXTERNAL_LIB_PREFIX)) { |
| cp = cp.substring(BaseStorageHook.EXTERNAL_LIB_PREFIX.length()); |
| // find external library using system property substitution |
| ClasspathEntry cpEntry = hostmanager.getExternalClassPath(BaseStorageHook.substituteVars(cp), sourcedata, sourcedomain); |
| if (cpEntry != null) { |
| cpEntries.add(cpEntry); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private boolean addInternalClassPath(String var, ArrayList cpEntries, String cp, ClasspathManager hostloader, BaseData sourcedata, ProtectionDomain sourcedomain) { |
| if (var.equals("ws")) //$NON-NLS-1$ |
| return ClasspathManager.addClassPathEntry(cpEntries, "ws/" + EclipseEnvironmentInfo.getDefault().getWS() + cp.substring(4), hostloader, sourcedata, sourcedomain); //$NON-NLS-1$ |
| if (var.equals("os")) //$NON-NLS-1$ |
| return ClasspathManager.addClassPathEntry(cpEntries, "os/" + EclipseEnvironmentInfo.getDefault().getOS() + cp.substring(4), hostloader, sourcedata, sourcedomain); //$NON-NLS-1$ |
| if (var.equals("nl")) { //$NON-NLS-1$ |
| cp = cp.substring(4); |
| for (int i = 0; i < NL_JAR_VARIANTS.length; i++) |
| if (ClasspathManager.addClassPathEntry(cpEntries, "nl/" + NL_JAR_VARIANTS[i] + cp, hostloader, sourcedata, sourcedomain)) //$NON-NLS-1$ |
| return true; |
| } |
| return false; |
| } |
| |
| //return a String representing the string found between the $s |
| private static String hasPrefix(String libPath) { |
| if (libPath.startsWith("$ws$")) //$NON-NLS-1$ |
| return "ws"; //$NON-NLS-1$ |
| if (libPath.startsWith("$os$")) //$NON-NLS-1$ |
| return "os"; //$NON-NLS-1$ |
| if (libPath.startsWith("$nl$")) //$NON-NLS-1$ |
| return "nl"; //$NON-NLS-1$ |
| return null; |
| } |
| |
| private static String[] buildNLJarVariants(String nl) { |
| ArrayList result = new ArrayList(); |
| nl = nl.replace('_', '/'); |
| while (nl.length() > 0) { |
| result.add("nl/" + nl + "/"); //$NON-NLS-1$ //$NON-NLS-2$ |
| int i = nl.lastIndexOf('/'); |
| nl = (i < 0) ? "" : nl.substring(0, i); //$NON-NLS-1$ |
| } |
| result.add(""); //$NON-NLS-1$ |
| return (String[]) result.toArray(new String[result.size()]); |
| } |
| |
| public void recordClassDefine(String name, Class clazz, byte[] classbytes, ClasspathEntry classpathEntry, BundleEntry entry, ClasspathManager manager) { |
| // do nothing |
| } |
| |
| public String findLibrary(BaseData data, String libName) { |
| if (libName.length() == 0) |
| return null; |
| if (libName.charAt(0) == '/' || libName.charAt(0) == '\\') |
| libName = libName.substring(1); |
| String mappedLibName = System.mapLibraryName(libName); |
| String result = searchVariants(data, mappedLibName); |
| if (result != null) |
| return result; |
| String[] mappedLibNames = BaseClassLoadingHook.mapLibraryNames(mappedLibName); |
| for (int i = 0; i < mappedLibNames.length && result == null; i++) |
| result = searchVariants(data, mappedLibNames[i]); |
| return result; |
| } |
| |
| private String searchVariants(BaseData bundledata, String path) { |
| for (int i = 0; i < LIB_VARIANTS.length; i++) { |
| BundleFile baseBundleFile = bundledata.getBundleFile(); |
| BundleEntry libEntry = baseBundleFile.getEntry(LIB_VARIANTS[i] + path); |
| if (libEntry != null) { |
| File libFile = baseBundleFile.getFile(LIB_VARIANTS[i] + path, true); |
| if (libFile == null) |
| return null; |
| // see bug 88697 - HP requires libraries to have executable permissions |
| if (org.eclipse.osgi.service.environment.Constants.OS_HPUX.equals(EclipseEnvironmentInfo.getDefault().getOS())) { |
| try { |
| // use the string array method in case there is a space in the path |
| Runtime.getRuntime().exec(new String[] {"chmod", "755", libFile.getAbsolutePath()}).waitFor(); //$NON-NLS-1$ //$NON-NLS-2$ |
| } catch (Exception e) { |
| e.printStackTrace(); |
| } |
| } |
| return libFile.getAbsolutePath(); |
| } |
| } |
| return null; |
| } |
| |
| public ClassLoader getBundleClassLoaderParent() { |
| return null; // do nothing |
| } |
| |
| public void addHooks(HookRegistry hookRegistry) { |
| hookRegistry.addClassLoadingHook(this); |
| } |
| |
| public BaseClassLoader createClassLoader(ClassLoader parent, ClassLoaderDelegate delegate, BundleProtectionDomain domain, BaseData data, String[] bundleclasspath) { |
| // TODO Auto-generated method stub |
| return null; |
| } |
| |
| public void initializedClassLoader(BaseClassLoader baseClassLoader, BaseData data) { |
| // TODO Auto-generated method stub |
| |
| } |
| } |