/*
* Copyright 2003-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jetbrains.mps.reloading;
import jetbrains.mps.util.ClassPathReader;
import jetbrains.mps.util.ClassType;
import jetbrains.mps.util.Pair;
import jetbrains.mps.util.PathManager;
import jetbrains.mps.util.SystemInfo;
import jetbrains.mps.util.URLUtil;
import jetbrains.mps.vfs.impl.IoFile;
import jetbrains.mps.vfs.path.UniPath;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import sun.misc.Launcher;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public final class CommonPaths {
private static final Logger LOG = LogManager.getLogger(CommonPaths.class);
private static final String REQUESTER_STRING = "Common paths";
private static final ClassPathCachingFacility ourClassPathCachingFacility = ClassPathCachingFacility.getInstance();
//--------paths-----------
public static List<String> getMPSPaths(ClassType type) {
if (type == ClassType.JDK) {
return getJDKPath();
} else if (type == ClassType.JDK_TOOLS) {
return getJDK_ToolsPath();
}
final CompositeClassPathItem result = new CompositeClassPathItem();
for (String path : new ClassPathReader(PathManager.getHomePath(), Collections.singletonList(type)).read()) {
addIfExists(result, path);
}
if (type == ClassType.ANNOTATIONS) {
addAnnotations(result);
} else if (type == ClassType.OPENAPI) {
addOpenAPIJars(result);
} else if (type == ClassType.CORE) {
addCoreJars(result);
} else if (type == ClassType.EDITOR) {
addEditorJars(result);
} else if (type == ClassType.IDEA_PLATFORM) {
addRepackedIdeaJars(result);
} else if (type == ClassType.IDEA) {
addIdeaJars(result);
} else if (type == ClassType.PLATFORM) {
addPlatformJars(result);
} else if (type == ClassType.WORKBENCH) {
addWorkbenchJars(result);
} else if (type == ClassType.TEST) {
addTestJars(result);
}
return itemToPath(result);
}
public static List<String> getJDKPath() {
return itemToPath(getJDKClassPath());
}
private static List<String> getJDK_ToolsPath() {
String jarLocation = getJarFileLocation("com.sun.jdi.Field");
if (jarLocation != null) {
File file = new File(jarLocation);
if (file.exists()) {
return Collections.singletonList(file.getAbsolutePath());
}
}
return Collections.emptyList();
}
private static String getJarFileLocation(@NotNull String classFQName) {
try {
Class cls = Class.forName(classFQName);
String classFileResourceLocation = "/" + classFQName.replaceAll("\\.", "/") + ".class";
String classFileResourceURL = cls.getResource(classFileResourceLocation).toString();
Pair<String, String> urls = URLUtil.splitJarUrl(classFileResourceURL);
if (urls == null) {
return null;
}
return URLDecoder.decode(urls.o1, Charset.defaultCharset().name()).replace('/', File.separatorChar);
} catch (ClassNotFoundException | UnsupportedEncodingException e) {
LOG.warn("", e);
return null;
}
}
public static String getBaseMPSPath() {
String classesPath = PathManager.getHomePath() + File.separator + "classes";
if (new File(classesPath).exists()) {
return classesPath;
}
String mpsJarPath = PathManager.getHomePath() + File.separator + "lib" + File.separatorChar + "mps-boot.jar";
if (new File(mpsJarPath).exists()) {
return mpsJarPath;
}
return null;
}
//------classpaths : JDK--------
private static List<String> getJDKJars() {
List<String> result = new ArrayList<String>();
if (SystemInfo.isMac && !SystemInfo.isJavaVersionAtLeast("1.7")) {
// in apple jdk's (< jdk7) rt.jar classes contains in classes.jar
result.add("classes.jar");
} else {
result.add("rt.jar");
}
result.add("jsse.jar");
result.add("jce.jar");
result.add("charsets.jar");
return result;
}
/**
* @deprecated Since MPS 3.3 used only inside this class, so should become private.
*/
@Deprecated
public static IClassPathItem getJDKClassPath() {
CompositeClassPathItem composite = new CompositeClassPathItem();
for (String s : getJDKJars()) {
addJarForName(composite, s);
}
return composite;
}
private static void addJarForName(CompositeClassPathItem composite, String name) {
RealClassPathItem rtJar = findBootstrapJarByName(name);
if (rtJar != null) {
composite.add(rtJar);
} else {
LOG.error("Can't find " + name + ". Make sure you are using JDK 5.0");
}
}
private static RealClassPathItem findBootstrapJarByName(String name) {
for (URL url : Launcher.getBootstrapClassPath().getURLs()) {
try {
File file = new File(url.toURI());
if (!file.exists()) continue;
if (file.getName().equals(name)) {
String canonicalPath = file.getCanonicalPath();
return ourClassPathCachingFacility.createFromPath(canonicalPath, REQUESTER_STRING);
}
} catch (URISyntaxException | IOException e) {
LOG.error(null, e);
}
}
return null;
}
//------classpaths : MPS--------
public static IClassPathItem getMPSClassPath() {
CompositeClassPathItem result = new CompositeClassPathItem();
addCoreJars(result);
addEditorJars(result);
addPlatformJars(result);
addIdeaJars(result);
addWorkbenchJars(result);
addClasses(result);
return result;
}
private static void addAnnotations(CompositeClassPathItem result) {
addIfExists(result, "lib/annotations.jar");
}
private static void addOpenAPIJars(CompositeClassPathItem result) {
addIfExists(result, "lib/mps-openapi.jar");
}
private static void addCoreJars(CompositeClassPathItem result) {
addIfExists(result, "lib/mps-annotations.jar");
addIfExists(result, "lib/mps-logging.jar");
addIfExists(result, "lib/mps-messaging.jar");
addIfExists(result, "lib/mps-core.jar");
addIfExists(result, "lib/mps-boot-util.jar");
addIfExists(result, "lib/mps-closures.jar");
addIfExists(result, "lib/mps-collections.jar");
addIfExists(result, "lib/mps-tuples.jar");
addIfExists(result, "lib/log4j.jar");
addIfExists(result, "lib/trove4j.jar");
addIfExists(result, "lib/jdom.jar");
addIfExists(result, "lib/ecj-4.6.2.jar");
addIfExists(result, "lib/guava-19.0.jar");
addIfExists(result, "lib/xstream-1.4.8.jar");
addIfExists(result, "lib/diffutils-1.2.1.jar");
addIfExists(result, "lib/asm-all.jar");
}
private static void addEditorJars(CompositeClassPathItem result) {
addIfExists(result, "lib/mps-editor.jar");
addIfExists(result, "lib/mps-editor-api.jar");
addIfExists(result, "lib/mps-editor-runtime.jar");
}
private static void addRepackedIdeaJars(CompositeClassPathItem result) {
addIfExists(result, "lib/openapi.jar");
addIfExists(result, "lib/platform.jar");
}
private static void addIdeaJars(CompositeClassPathItem result) {
addRepackedIdeaJars(result);
addIfExists(result, "lib/netty-all-4.1.9.Final.jar");
addIfExists(result, "lib/sanselan-0.98-snapshot.jar");
addIfExists(result, "lib/util.jar");
addIfExists(result, "lib/extensions.jar");
addIfExists(result, "lib/picocontainer.jar");
addIfExists(result, "lib/forms_rt.jar");
}
private static void addPlatformJars(CompositeClassPathItem result) {
addIfExists(result, "lib/mps-platform.jar");
addIfExists(result, "lib/mps-icons.jar");
}
private static void addWorkbenchJars(CompositeClassPathItem result) {
addIfExists(result, "lib/mps-workbench.jar");
addIfExists(result, "lib/junit-4.12.jar");
}
private static void addTestJars(CompositeClassPathItem result) {
addIfExists(result, "lib/mps-test.jar");
addIfExists(result, "lib/mps-environment.jar");
addIfExists(result, "lib/junit-4.12.jar");
}
private static void addClasses(final CompositeClassPathItem result) {
String homePath = PathManager.getHomePath();
ClassPathReader classPathReader = new ClassPathReader(PathManager.getHomePath(), Arrays.asList(ClassType.values()));
classPathReader.read().stream().forEach(param -> {
File dir = new File(homePath, param);
if (dir.exists()) {
result.add(ourClassPathCachingFacility.createFromPath(dir.getAbsolutePath(), REQUESTER_STRING));
}
});
}
private static void addIfExists(CompositeClassPathItem item, String path) {
String dependentPath = UniPath.fromString(path).toSystemPath().toString(); // fixme waiting for Path#resolve method to resolve children in fs
for (String basePath : PathManager.getHomePaths()) {
UniPath fullPath = UniPath.fromString(basePath + File.separator + dependentPath).toSystemPath();
if (new IoFile(fullPath).exists()) {
item.add(ourClassPathCachingFacility.createFromPath(fullPath.toString(), REQUESTER_STRING));
}
}
}
//--------utils-----------
private static List<String> itemToPath(IClassPathItem cp) {
List<String> result = new ArrayList<String>();
for (IClassPathItem item : cp.flatten()) {
if (item instanceof FileClassPathItem) {
result.add(((FileClassPathItem) item).getPath());
} else if (item instanceof JarFileClassPathItem) {
result.add(((JarFileClassPathItem) item).getFile().getAbsolutePath());
} else {
throw new IllegalArgumentException(item.getClass().getName());
}
}
return result;
}
}