blob: 090db4366cc8d36918b58e6c500a09ad4238fcd8 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2019 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 - Initial API and implementation
******************************************************************************/
package org.eclipse.pde.internal.build.site;
import java.io.*;
import java.net.URL;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.eclipse.core.runtime.Platform;
import org.eclipse.osgi.util.ManifestElement;
import org.eclipse.pde.internal.build.IPDEBuildConstants;
import org.eclipse.pde.internal.build.Utils;
import org.osgi.framework.Bundle;
public class ProfileManager {
public static final String PROFILE_EXTENSION = ".profile"; //$NON-NLS-1$
public static final String SYSTEM_PACKAGES = "org.osgi.framework.system.packages"; //$NON-NLS-1$
public static final String PROFILE_NAME = "osgi.java.profile.name"; //$NON-NLS-1$
public static final String PROFILE_LIST = "profile.list"; //$NON-NLS-1$
public static final String JAVA_PROFILES = "java.profiles"; //$NON-NLS-1$
public static final String PROFILE_JAVAC_SOURCE = "org.eclipse.jdt.core.compiler.source"; //$NON-NLS-1$
public static final String PROFILE_JAVAC_TARGET = "org.eclipse.jdt.core.compiler.codegen.targetPlatform"; //$NON-NLS-1$
private final HashMap<String, Properties> profileMap = new HashMap<>();
private String[] profileSources = null;
public ProfileManager() {
loadProfiles(true);
}
public ProfileManager(String[] profileSources) {
this.profileSources = profileSources;
loadProfiles(false);
}
public ProfileManager(String[] profileSources, boolean includeRuntime) {
this.profileSources = profileSources;
loadProfiles(includeRuntime);
}
public Properties getProfileProperties(String profileName) {
return profileMap.get(profileName);
}
public void copyEEProfileProperties(Dictionary<String, Object> source, Properties target) {
String[] profiles = getJavaProfiles();
for (int i = 0; i < profiles.length; i++) {
Object value = source.get(profiles[i]);
if (value != null && value instanceof String) {
target.put(profiles[i], value);
}
}
}
/**
* Return the javacSource to use when compiling for the given execution environment
* @param environment
* @return javacSource or null
*/
public String getJavacSource(String environment) {
if (profileMap.containsKey(environment)) {
Properties properties = profileMap.get(environment);
return properties.getProperty(PROFILE_JAVAC_SOURCE);
}
if (environment.startsWith("JavaSE-")) { //$NON-NLS-1$
return environment.replace("JavaSE-", ""); //$NON-NLS-1$ //$NON-NLS-2$
}
return null;
}
/**
* Return the javacTarget to use when compiling for the given execution environment
* @param environment
* @return javacTarget or null
*/
public String getJavacTarget(String environment) {
if (profileMap.containsKey(environment)) {
Properties properties = profileMap.get(environment);
return properties.getProperty(PROFILE_JAVAC_TARGET);
}
return null;
}
public String[] getJavaProfiles() {
Set<String> keys = profileMap.keySet();
return sortProfiles(keys.toArray(new String[keys.size()]));
}
protected String[] sortProfiles(String[] profiles) {
Arrays.sort(profiles, new Comparator<String>() {
@Override
public int compare(String profile1, String profile2) {
// need to make sure JavaSE, J2SE profiles are sorted ahead of all other profiles
String p1 = profile1;
String p2 = profile2;
if (p1.startsWith("JavaSE-") && !p2.startsWith("JavaSE-")) //$NON-NLS-1$ //$NON-NLS-2$
return -1;
if (!p1.startsWith("JavaSE-") && p2.startsWith("JavaSE-")) //$NON-NLS-1$ //$NON-NLS-2$
return 1;
if (p1.startsWith("J2SE-") && !p2.startsWith("J2SE-")) //$NON-NLS-1$ //$NON-NLS-2$
return -1;
if (!p1.startsWith("J2SE-") && p2.startsWith("J2SE-")) //$NON-NLS-1$ //$NON-NLS-2$
return 1;
if (p1.startsWith("JavaSE/compact") && !p2.startsWith("JavaSE/compact")) //$NON-NLS-1$ //$NON-NLS-2$
return -1;
if (!p1.startsWith("JavaSE/compact") && p2.startsWith("JavaSE/compact")) //$NON-NLS-1$ //$NON-NLS-2$
return 1;
return -p1.compareTo(p2);
}
});
return profiles;
}
protected void loadProfiles(boolean includeRuntime) {
if (includeRuntime || profileSources == null) {
loadRuntimeJavaProfiles();
}
if (profileSources != null) {
for (int i = 0; i < profileSources.length; i++) {
File source = new File(profileSources[i]);
if (source.isDirectory()) {
loadJavaProfiles(source);
} else {
loadJarJavaProfiles(source);
}
}
}
}
protected void loadJarJavaProfiles(File bundleLocation) {
ZipFile zipFile = null;
try {
zipFile = new ZipFile(bundleLocation, ZipFile.OPEN_READ);
loadJavaProfiles(zipFile);
} catch (IOException e) {
// boo
} finally {
Utils.close(zipFile);
}
}
protected void loadRuntimeJavaProfiles() {
Bundle systemBundle = Platform.getBundle(IPDEBuildConstants.BUNDLE_OSGI);
if (systemBundle != null)
loadJavaProfiles(systemBundle);
}
/*
* Return an input stream on the profile.list entry in the given container.
*/
private InputStream getProfileListInputStream(Object container) {
if (container instanceof File) {
// try the profile list first
File listFile = new File((File) container, PROFILE_LIST);
if (listFile.exists())
try {
return new BufferedInputStream(new FileInputStream(listFile));
} catch (FileNotFoundException e) {
return null;
}
} else if (container instanceof ZipFile) {
ZipFile zipFile = (ZipFile) container;
ZipEntry listEntry = ((ZipFile) container).getEntry(PROFILE_LIST);
if (listEntry != null)
try {
return new BufferedInputStream(zipFile.getInputStream(listEntry));
} catch (IOException e) {
return null;
}
} else if (container instanceof Bundle) {
Bundle systemBundle = (Bundle) container;
URL url = systemBundle.getEntry(PROFILE_LIST);
if (url != null) {
try {
return new BufferedInputStream(url.openStream());
} catch (IOException e) {
return null;
}
}
}
return null;
}
/*
* Return an Enumeration containing all the profile entries in the container
* If profiles is null then:
* A ZipFile container returns all ZipEntries from the jar
* All other containers return the *.profile entries from the root
*/
@SuppressWarnings("rawtypes")
private Enumeration getProfilesEnum(Object container, String[] profiles) {
if (profiles != null) {
return Utils.getArrayEnumerator(profiles);
} else if (container instanceof File) {
File[] files = ((File) container).listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(PROFILE_EXTENSION);
}
});
return Utils.getArrayEnumerator(files);
} else if (container instanceof ZipFile) {
return ((ZipFile) container).entries();
} else if (container instanceof Bundle) {
return ((Bundle) container).findEntries("/", "*" + PROFILE_EXTENSION, false); //$NON-NLS-1$ //$NON-NLS-2$
}
return null;
}
private InputStream getEntryInputStream(Object container, Object entry) {
try {
if (entry instanceof String) {
if (container instanceof File)
entry = new File((File) container, (String) entry);
else if (container instanceof ZipFile)
entry = ((ZipFile) container).getEntry((String) entry);
else if (container instanceof Bundle)
entry = ((Bundle) container).getEntry((String) entry);
}
if (entry instanceof File)
return new BufferedInputStream(new FileInputStream((File) entry));
else if (entry instanceof ZipEntry)
return new BufferedInputStream(((ZipFile) container).getInputStream((ZipEntry) entry));
else if (entry instanceof URL)
return new BufferedInputStream(((URL) entry).openStream());
} catch (IOException e) {
// boo
}
return null;
}
/*
* ZipFile conainers aren't able to filter the entry enumeration, must filter here.
*/
private boolean isProfileEntry(Object entry) {
if (entry instanceof String || entry instanceof URL || entry instanceof File)
return true;
else if (entry instanceof ZipEntry) {
String entryName = ((ZipEntry) entry).getName();
return entryName.indexOf('/') < 0 && entryName.endsWith(PROFILE_EXTENSION);
}
return false;
}
/**
* Load the Java Profiles from the given container. A container is one of:
* File - a directory shaped bundle on disk
* ZipFile - a jar shaped bundle on disk
* Bundle - a Bundle object from the current runtime.
* @param container : The container to load java profiles from.
*/
private void loadJavaProfiles(Object container) {
InputStream is = getProfileListInputStream(container);
String[] profiles = getJavaProfiles(is);
Utils.close(is);
Enumeration<?> entries = getProfilesEnum(container, profiles);
while (entries != null && entries.hasMoreElements()) {
Object item = entries.nextElement();
if (!isProfileEntry(item))
continue;
is = getEntryInputStream(container, item);
if (is != null) {
Properties props = new Properties();
try {
props.load(is);
if (props.containsKey(PROFILE_NAME))
profileMap.put((String) props.get(PROFILE_NAME), props);
} catch (IOException e) {
//boo
} finally {
Utils.close(is);
}
}
}
}
private String[] getJavaProfiles(InputStream is) {
if (is == null)
return null;
Properties props = new Properties();
try {
props.load(is);
} catch (IOException e) {
return null;
}
return ManifestElement.getArrayFromList(props.getProperty(JAVA_PROFILES), ","); //$NON-NLS-1$
}
}