/**********************************************************************
* Copyright (c) 2005-2009 ant4eclipse project team.
*
* 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:
* Nils Hartmann, Daniel Kasmeroglu, Gerd Wuetherich
**********************************************************************/
package org.ant4eclipse.lib.jdt.internal.model.jre;
import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import java.util.StringTokenizer;
import org.ant4eclipse.lib.core.Assure;
import org.ant4eclipse.lib.core.data.Version;
import org.ant4eclipse.lib.core.exception.Ant4EclipseException;
import org.ant4eclipse.lib.core.logging.A4ELogging;
import org.ant4eclipse.lib.core.service.ServiceRegistryAccess;
import org.ant4eclipse.lib.core.util.Utilities;
import org.ant4eclipse.lib.jdt.JdtExceptionCode;
import org.ant4eclipse.lib.jdt.internal.model.jre.support.LibraryDetector;
import org.ant4eclipse.lib.jdt.model.jre.JavaProfile;
import org.ant4eclipse.lib.jdt.model.jre.JavaRuntime;
import org.ant4eclipse.lib.jdt.model.jre.JavaRuntimeRegistry;
public class JavaRuntimeLoader {
/** */
private static final String JAVA_SPECIFICATION_NAME = "java.specification.name";
/** */
private static final String JAVA_SPECIFICATION_VERSION = "java.specification.version";
/** J2ME configuration property name */
private static final String J2ME_MICROEDITION_CONFIGURATION = "microedition.configuration"; //$NON-NLS-1$
/** J2ME profile property name */
private static final String J2ME_MICROEDITION_PROFILES = "microedition.profiles"; //$NON-NLS-1$
/** */
private static String J2SE = "J2SE-"; //$NON-NLS-1$
/** */
private static String JAVASE = "JavaSE-"; //$NON-NLS-1$
/**
* @param id
* @param location
* @param files
* the list of (jar-)files defining this java runtime or null if the file should be determined from the
* JavaRuntime's location
*/
public static JavaRuntime loadJavaRuntime(String id, File location, String extDirs, String endorsedDirs,
List<File> files) {
Assure.nonEmpty("id", id);
Assure.isDirectory("location", location);
String outfileName = System.getProperty("java.io.tmpdir") + File.separatorChar + "ant4eclipse_jdk_props_"
+ Math.round(Math.random() * 1000000000);
// System.out.println(outfileName);
JavaExecuter javaLauncher = JavaExecuter.createWithA4eClasspath(location);
javaLauncher.setMainClass(LibraryDetector.class.getName());
javaLauncher.setArgs(new String[] { outfileName });
javaLauncher.execute();
// TODO
StringBuffer contents = new StringBuffer();
try {
File file = new File(outfileName);
contents = Utilities.readTextContent(file, Utilities.ENCODING, false);
file.deleteOnExit();
} catch (Throwable e) {
e.printStackTrace();
}
String result = contents.toString();
// System.out.println(result);
String[] values = result.split("\\|");
Version javaVersion = Version.newStandardVersion(values[0]);
String sunbootclasspath = values[1];
String javaextdirs = (extDirs != null ? extDirs : values[2]);
String javaendorseddirs = (endorsedDirs != null ? endorsedDirs : values[3]);
Version javaSpecificationVersion = Version.newBundleVersion(values[4]);
if (files != null) {
A4ELogging.debug("Using specified files for JRE '%s': '%s'", id, files);
} else {
files = new LinkedList<File>();
A4ELogging.debug("Adding endorsed files from endorsed dirs for JRE '%s': '%s'", id, javaendorseddirs);
addFiles(javaendorseddirs, false, files);
addFiles(sunbootclasspath, false, files);
A4ELogging.debug("Adding ext files from exts dirs for JRE '%s': '%s'", id, javaextdirs);
addFiles(javaextdirs, true, files);
}
File[] libraries = files.toArray(new File[0]);
//
Properties properties = new Properties();
properties.put(JAVA_SPECIFICATION_VERSION, values[4]);
properties.put(JAVA_SPECIFICATION_NAME, values[5]);
String javaProfileName = getVmProfile(properties);
JavaRuntimeRegistry javaRuntimeRegistry = ServiceRegistryAccess.instance().getService(JavaRuntimeRegistry.class);
if (!javaRuntimeRegistry.hasJavaProfile(javaProfileName)) {
A4ELogging.error("No Java-Profile with name '%s' found for JRE '%s' located at '%s'. Known Profiles: '%s'",
javaProfileName, id, location, javaRuntimeRegistry.getAllJavaProfileNames());
throw new Ant4EclipseException(JdtExceptionCode.NO_JAVA_PROFILE_FOUND_FOR_JRE, id, location, javaProfileName);
}
JavaProfile javaProfile = javaRuntimeRegistry.getJavaProfile(javaProfileName);
JavaRuntime javaRuntime = new JavaRuntimeImpl(id, location, libraries, javaVersion, javaSpecificationVersion,
javaProfile);
return javaRuntime;
}
private static void addFiles(String path, boolean addChildrenIfDirectory, List<File> list) {
String[] fileNames = path.split(File.pathSeparator);
for (String fileName : fileNames) {
File file = new File(fileName);
if (file.exists()) {
if (file.isFile() && !list.contains(file)) {
list.add(file);
} else if (file.isDirectory() && addChildrenIfDirectory) {
File[] children = file.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.endsWith(".jar");
}
});
for (File child : children) {
if (child.isFile() && !list.contains(child)) {
list.add(child);
}
}
}
}
}
}
private static String getVmProfile(Properties systemProperties) {
// Properties result = new Properties();
// Find the VM profile name using J2ME properties
String j2meConfig = systemProperties.getProperty(J2ME_MICROEDITION_CONFIGURATION);
String j2meProfiles = systemProperties.getProperty(J2ME_MICROEDITION_PROFILES);
String vmProfile = null;
String javaEdition = null;
if ((j2meConfig != null) && (j2meConfig.length() > 0) && (j2meProfiles != null) && (j2meProfiles.length() > 0)) {
// save the vmProfile based off of the config and profile
// use the last profile; assuming that is the highest one
String[] j2meProfileList = getArrayFromList(j2meProfiles, " "); //$NON-NLS-1$
if ((j2meProfileList != null) && (j2meProfileList.length > 0)) {
vmProfile = j2meConfig + '_' + j2meProfileList[j2meProfileList.length - 1];
}
} else {
// No J2ME properties; use J2SE properties
// Note that the CDC spec appears not to require VM implementations to set the
// javax.microedition properties!! So we will try to fall back to the
// java.specification.name property, but this is pretty ridiculous!!
String javaSpecVersion = systemProperties.getProperty(JAVA_SPECIFICATION_VERSION);
// set the profile and EE based off of the java.specification.version
// TODO We assume J2ME Foundation and J2SE here. need to support other profiles J2EE ...
if (javaSpecVersion != null) {
StringTokenizer st = new StringTokenizer(javaSpecVersion, " _-"); //$NON-NLS-1$
javaSpecVersion = st.nextToken();
String javaSpecName = systemProperties.getProperty(JAVA_SPECIFICATION_NAME);
if ("J2ME Foundation Specification".equals(javaSpecName)) {
vmProfile = "CDC-" + javaSpecVersion + "_Foundation-" + javaSpecVersion; //$NON-NLS-1$ //$NON-NLS-2$
} else {
javaEdition = J2SE;
if (Integer.parseInt(javaSpecVersion.split("\\.")[1]) >= 6) {
javaEdition = JAVASE;
}
vmProfile = javaEdition + javaSpecVersion;
}
}
}
return vmProfile;
}
/**
* Returns the result of converting a list of tokens into an array. The tokens are split using the specified
* separator.
*
* @return the array of string tokens. If there are none then an empty array is returned.
* @param stringList
* the initial string list
* @param separator
* the separator to use to split the list into tokens.
* @since 3.2
*/
private static String[] getArrayFromList(String stringList, String separator) {
if ((stringList == null) || (stringList.trim().length() == 0)) {
return new String[0];
}
ArrayList<String> list = new ArrayList<String>();
StringTokenizer tokens = new StringTokenizer(stringList, separator);
while (tokens.hasMoreTokens()) {
String token = tokens.nextToken().trim();
if (token.length() != 0) {
list.add(token);
}
}
return list.toArray(new String[list.size()]);
}
}