blob: 76bdc96b1cd191dc67a9602555b60ed4807825a3 [file] [log] [blame]
/*
* Copyright 2000-2013 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 com.intellij.appengine.sdk.impl;
import com.intellij.appengine.sdk.AppEngineSdk;
import com.intellij.appengine.util.AppEngineUtil;
import com.intellij.execution.configurations.ParametersList;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.io.JarUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.util.containers.ContainerUtil;
import gnu.trove.THashMap;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.appengine.model.impl.JpsAppEngineModuleExtensionImpl;
import java.io.*;
import java.util.*;
import java.util.jar.Attributes;
/**
* @author nik
*/
public class AppEngineSdkImpl implements AppEngineSdk {
private static final Logger LOG = Logger.getInstance("#com.intellij.appengine.sdk.impl.AppEngineSdkImpl");
private Map<String, Set<String>> myClassesWhiteList;
private Map<String, Set<String>> myMethodsBlackList;
private final String myHomePath;
public AppEngineSdkImpl(String homePath) {
myHomePath = homePath;
}
public File getAppCfgFile() {
final String extension = SystemInfo.isWindows ? "cmd" : "sh";
return new File(FileUtil.toSystemDependentName(myHomePath + "/bin/appcfg." + extension));
}
public File getWebSchemeFile() {
return new File(FileUtil.toSystemDependentName(myHomePath + "/docs/appengine-web.xsd"));
}
public File getToolsApiJarFile() {
final String path = FileUtil.toSystemDependentName(myHomePath + JpsAppEngineModuleExtensionImpl.LIB_APPENGINE_TOOLS_API_JAR);
return new File(path);
}
public File[] getLibraries() {
File sdkHome = new File(FileUtil.toSystemDependentName(myHomePath));
return getJarsFromDirectory(new File(sdkHome, "lib" + File.separator + "shared"));
}
@Override
public File[] getJspLibraries() {
File sdkHome = new File(FileUtil.toSystemDependentName(myHomePath));
return getJarsFromDirectory(new File(sdkHome, "lib" + File.separator + "shared" + File.separator + "jsp"));
}
public void patchJavaParametersForDevServer(ParametersList vmParameters) {
final String agentPath = myHomePath + "/lib/agent/appengine-agent.jar";
if (new File(FileUtil.toSystemDependentName(agentPath)).exists()) {
vmParameters.add("-javaagent:" + agentPath);
}
String patchPath = myHomePath + "/lib/override/appengine-dev-jdk-overrides.jar";
if (new File(FileUtil.toSystemDependentName(patchPath)).exists()) {
vmParameters.add("-Xbootclasspath/p:" + patchPath);
}
}
private static File[] getJarsFromDirectory(File libFolder) {
List<File> jars = new ArrayList<File>();
final File[] files = libFolder.listFiles();
if (files != null) {
for (File file : files) {
if (file.isFile() && file.getName().endsWith(".jar")) {
jars.add(file);
}
}
}
return jars.toArray(new File[jars.size()]);
}
@NotNull
public String getSdkHomePath() {
return myHomePath;
}
public boolean isClassInWhiteList(@NotNull String className) {
if (!isValid()) return true;
if (myClassesWhiteList == null) {
File cachedWhiteList = getCachedWhiteListFile();
if (cachedWhiteList.exists()) {
try {
myClassesWhiteList = AppEngineSdkUtil.loadWhiteList(cachedWhiteList);
}
catch (IOException e) {
LOG.error(e);
myClassesWhiteList = Collections.emptyMap();
}
}
else {
myClassesWhiteList = AppEngineSdkUtil.computeWhiteList(getToolsApiJarFile());
if (!myClassesWhiteList.isEmpty()) {
AppEngineSdkUtil.saveWhiteList(cachedWhiteList, myClassesWhiteList);
}
}
}
if (myClassesWhiteList.isEmpty()) {
//don't report errors if white-list wasn't properly loaded
return true;
}
final String packageName = StringUtil.getPackageName(className);
final String name = StringUtil.getShortName(className);
final Set<String> classes = myClassesWhiteList.get(packageName);
return classes != null && classes.contains(name);
}
@Override
@Nullable
public String getVersion() {
return JarUtil.getJarAttribute(getToolsApiJarFile(), "com/google/appengine/tools/info/", Attributes.Name.SPECIFICATION_VERSION);
}
private File getCachedWhiteListFile() {
String fileName = StringUtil.getShortName(myHomePath, '/') + Integer.toHexString(myHomePath.hashCode()) + "_" + Long.toHexString(getToolsApiJarFile().lastModified());
return new File(AppEngineUtil.getAppEngineSystemDir(), fileName);
}
public boolean isMethodInBlacklist(@NotNull String className, @NotNull String methodName) {
if (myMethodsBlackList == null) {
try {
myMethodsBlackList = loadBlackList();
}
catch (IOException e) {
LOG.error(e);
myMethodsBlackList = new THashMap<String, Set<String>>();
}
}
final Set<String> methods = myMethodsBlackList.get(className);
return methods != null && methods.contains(methodName);
}
public boolean isValid() {
return getToolsApiJarFile().exists() && getAppCfgFile().exists();
}
public String getOrmLibDirectoryPath() {
return getLibUserDirectoryPath() + "/orm";
}
@Override
public List<String> getUserLibraryPaths() {
List<String> result = new ArrayList<String>();
result.add(getLibUserDirectoryPath());
File opt = new File(myHomePath, "lib/opt/user");
ContainerUtil.addIfNotNull(result, findLatestVersion(new File(opt, "appengine-endpoints")));
ContainerUtil.addIfNotNull(result, findLatestVersion(new File(opt, "jsr107")));
return result;
}
private static String findLatestVersion(File dir) {
String[] names = dir.list();
if (names != null && names.length > 0) {
String max = Collections.max(Arrays.asList(names));
return FileUtil.toSystemIndependentName(new File(dir, max).getAbsolutePath());
}
return null;
}
public VirtualFile[] getOrmLibSources() {
final File libsDir = new File(FileUtil.toSystemDependentName(myHomePath + "/src/orm"));
final File[] files = libsDir.listFiles();
List<VirtualFile> roots = new ArrayList<VirtualFile>();
if (files != null) {
for (File file : files) {
final String url = VfsUtil.getUrlForLibraryRoot(file);
final VirtualFile zipRoot = VirtualFileManager.getInstance().findFileByUrl(url);
if (zipRoot != null && zipRoot.isDirectory()) {
String fileName = file.getName();
final String srcDirName = StringUtil.trimEnd(fileName, "-src.zip");
final VirtualFile sourcesDir = zipRoot.findFileByRelativePath(srcDirName + "/src/java");
if (sourcesDir != null) {
roots.add(sourcesDir);
}
else {
roots.add(zipRoot);
}
}
}
}
return VfsUtilCore.toVirtualFileArray(roots);
}
public String getLibUserDirectoryPath() {
return myHomePath + "/lib/user";
}
private Map<String, Set<String>> loadBlackList() throws IOException {
final InputStream stream = getClass().getResourceAsStream("/data/methodsBlacklist.txt");
LOG.assertTrue(stream != null, "/data/methodsBlacklist.txt not found");
final THashMap<String, Set<String>> map = new THashMap<String, Set<String>>();
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
try {
String line;
while ((line = reader.readLine()) != null) {
final int i = line.indexOf(':');
String className = line.substring(0, i);
String methods = line.substring(i + 1);
map.put(className, new THashSet<String>(StringUtil.split(methods, ",")));
}
}
finally {
reader.close();
}
return map;
}
}