/* * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. * A copy of the License is located at * * http://aws.amazon.com/apache2.0 * * or in the "license" file accompanying this file. This file 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.amazonaws.eclipse.lambda.project.wizard.util; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintStream; import java.util.Properties; import org.eclipse.core.filesystem.EFS; import org.eclipse.core.filesystem.IFileStore; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.JavaCore; import com.amazonaws.eclipse.lambda.LambdaPlugin; import com.amazonaws.eclipse.lambda.project.metadata.LambdaFunctionProjectMetadata; import com.amazonaws.eclipse.lambda.project.template.CodeTemplateManager; import com.amazonaws.eclipse.lambda.project.template.data.HandlerClassTemplateData; import com.amazonaws.eclipse.lambda.project.template.data.HandlerTestClassTemplateData; import com.amazonaws.eclipse.lambda.project.template.data.StreamHandlerClassTemplateData; import com.amazonaws.eclipse.lambda.project.template.data.StreamHandlerTestClassTemplateData; import com.amazonaws.eclipse.lambda.project.wizard.model.LambdaFunctionWizardDataModel; import freemarker.template.Template; public class FunctionProjectUtil { private static final String LAMBDA_PROJECT_SETTING_FILE = "com.amazonaws.eclipse.lambda.project"; public static void addSourceToProject(IProject project, LambdaFunctionWizardDataModel dataModel) { if (dataModel.isUseStreamHandler()) { StreamHandlerClassTemplateData streamHandlerClassData = dataModel.collectStreamHandlerTemplateData(); addStreamHandlerClassToProject(project, streamHandlerClassData); StreamHandlerTestClassTemplateData streamHandlerTestClassData = dataModel.collectStreamHandlerTestTemplateData(); addStreamHandlerTestClassToProject(project, streamHandlerTestClassData); } else { // Add handler class HandlerClassTemplateData handlerClassData = dataModel.collectHandlerTemplateData(); addHandlerClassToProject(project, handlerClassData); // Add handler test class HandlerTestClassTemplateData handlerTestClassData = dataModel.collectHandlerTestTemplateData(); addHandlerTestClassToProject(project, handlerTestClassData); addTestContextToProject(project, handlerTestClassData); if (dataModel.getPredefinedHandlerInputType() != null) { addTestUtilsToProject(project, handlerTestClassData); } // Add input json file if the user selects the predefined input type if (dataModel.getPredefinedHandlerInputType() != null) { String jsonFileName = dataModel.getPredefinedHandlerInputType() .getSampleInputJsonFile(); addSampleInputJsonFileToProject(project, handlerTestClassData.getPackageName(), jsonFileName); } } addTestDirectoryToClasspath(project); } private static void addHandlerClassToProject(IProject project, HandlerClassTemplateData templateData) { try { Template handlerTemplate = CodeTemplateManager.getInstance() .getHandlerClassTemplate(); String fileContent = CodeTemplateManager.processTemplateWithData( handlerTemplate, templateData); FunctionProjectUtil.addSourceClassToProject( project, JavaPackageName.parse(templateData.getPackageName()), templateData.getHandlerClassName(), fileContent); } catch (Exception e) { LambdaPlugin.getDefault().reportException( "Failed to add source to the new Lambda function project", e); throw new RuntimeException(e); } } private static void addHandlerTestClassToProject(IProject project, HandlerTestClassTemplateData templateData) { try { Template testTemplate = CodeTemplateManager.getInstance() .getHandlerTestClassTemplate(); String fileContent = CodeTemplateManager.processTemplateWithData( testTemplate, templateData); FunctionProjectUtil.addTestClassToProject( project, JavaPackageName.parse(templateData.getPackageName()), templateData.getHandlerTestClassName(), fileContent); } catch (Exception e) { LambdaPlugin.getDefault().reportException( "Failed to add test class to the new Lambda function project", e); throw new RuntimeException(e); } } private static void addStreamHandlerClassToProject(IProject project, StreamHandlerClassTemplateData templateData) { try { Template streamHandlerTemplate = CodeTemplateManager.getInstance() .getStreamHandlderClassTemplate(); String fileContent = CodeTemplateManager.processTemplateWithData( streamHandlerTemplate, templateData); FunctionProjectUtil.addSourceClassToProject( project, JavaPackageName.parse(templateData.getPackageName()), templateData.getHandlerClassName(), fileContent); } catch (Exception e) { LambdaPlugin.getDefault().reportException( "Failed to add source to the new Lambda function project", e); throw new RuntimeException(e); } } private static void addStreamHandlerTestClassToProject(IProject project, StreamHandlerTestClassTemplateData templateData) { try { Template testTemplate = CodeTemplateManager.getInstance() .getStreamHandlerTestClassTemplate(); String fileContent = CodeTemplateManager.processTemplateWithData( testTemplate, templateData); FunctionProjectUtil.addTestClassToProject( project, JavaPackageName.parse(templateData.getPackageName()), templateData.getHandlerTestClassName(), fileContent); } catch (Exception e) { LambdaPlugin.getDefault().reportException( "Failed to add test class to the new Lambda function project", e); throw new RuntimeException(e); } } private static void addTestContextToProject( IProject project, HandlerTestClassTemplateData templateData) { try { Template template = CodeTemplateManager.getInstance() .getTestContextTemplate(); String content = CodeTemplateManager.processTemplateWithData( template, templateData); FunctionProjectUtil.addTestClassToProject( project, JavaPackageName.parse(templateData.getPackageName()), "TestContext", content); } catch (Exception e) { LambdaPlugin.getDefault().reportException( "Failed to add test context to the new Lambda function project", e); if (e instanceof RuntimeException) { throw (RuntimeException) e; } throw new RuntimeException(e); } } private static void addTestUtilsToProject( IProject project, HandlerTestClassTemplateData templateData) { try { Template template = CodeTemplateManager.getInstance() .getTestUtilsTemplate(); String content = CodeTemplateManager.processTemplateWithData( template, templateData); FunctionProjectUtil.addTestClassToProject( project, JavaPackageName.parse(templateData.getPackageName()), "TestUtils", content); } catch (Exception e) { LambdaPlugin.getDefault().reportException( "Failed to add test utils to the new Lambda function project", e); if (e instanceof RuntimeException) { throw (RuntimeException) e; } throw new RuntimeException(e); } } private static void addSampleInputJsonFileToProject(IProject project, String testPackageName, String jsonFileName) { try { Template jsonFileTemplate = CodeTemplateManager.getInstance() .getTestInputJsonFileTemplate(jsonFileName); String fileContent = CodeTemplateManager.processTemplateWithData( jsonFileTemplate, null); FunctionProjectUtil.addTestResourceToProject( project, JavaPackageName.parse(testPackageName), jsonFileName, fileContent); } catch (Exception e) { LambdaPlugin.getDefault().reportException( "Failed to add test resource to the new Lambda function project", e); throw new RuntimeException(e); } } public static File addReadmeFileToProject(IProject project, HandlerTestClassTemplateData templateData) { try { Template readmeFileTemplate = CodeTemplateManager.getInstance() .getReadmeHtmlFileTemplate(); String fileContent = CodeTemplateManager.processTemplateWithData( readmeFileTemplate, templateData); return FunctionProjectUtil.addReadmeFileToProject(project, fileContent); } catch (Exception e) { LambdaPlugin.getDefault().reportException( "Failed to add README.html to the new Lambda function project", e); throw new RuntimeException(e); } } private static void addTestDirectoryToClasspath(IProject project) { try { IJavaProject javaProj = JavaCore.create(project); IFolder tstFolder = project.getFolder("tst"); IPackageFragmentRoot tstRoot = javaProj.getPackageFragmentRoot(tstFolder); if (javaProj.isOnClasspath(tstRoot)) return; IClasspathEntry[] originalCp = javaProj.getRawClasspath(); IClasspathEntry[] augmentedCp = new IClasspathEntry[originalCp.length + 1]; System.arraycopy(originalCp, 0, augmentedCp, 0, originalCp.length); augmentedCp[originalCp.length] = JavaCore.newSourceEntry(tstRoot.getPath()); javaProj.setRawClasspath(augmentedCp, null); } catch (Exception e) { LambdaPlugin.getDefault().warn( "Failed to add tst directory to the classpath", e); } } /** * @param project * the target project where the source is added * @param packageName * the Java package name of the class being added * @param className * the name of the class. * @param classContent * the content of the class */ private static void addSourceClassToProject(IProject project, JavaPackageName packageName, String className, String classContent) throws CoreException, FileNotFoundException { IPath srcRoot = getProjectDirectory(project, "src"); String fileName = className + ".java"; addClassToProject(srcRoot, packageName, fileName, classContent); } private static void addTestClassToProject(IProject project, JavaPackageName packageName, String className, String classContent) throws CoreException, FileNotFoundException { IPath tstRoot = getProjectDirectory(project, "tst"); String fileName = className + ".java"; addClassToProject(tstRoot, packageName, fileName, classContent); } private static void addTestResourceToProject(IProject project, JavaPackageName packageName, String fileName, String fileContent) throws FileNotFoundException, CoreException { IPath tstRoot = getProjectDirectory(project, "tst"); addClassToProject(tstRoot, packageName, fileName, fileContent); } private static File addReadmeFileToProject(IProject project, String fileContent) throws FileNotFoundException, CoreException { IPath projectRoot = getProjectDirectory(project, null); return addFileToProject(projectRoot, "README.html", fileContent); } private static void addClassToProject(IPath root, JavaPackageName packageName, String fileName, String classContent) throws CoreException, FileNotFoundException { IPath targetPath = root; for (String component : packageName.getComponents()) { targetPath = targetPath.append(component); } addFileToProject(targetPath, fileName, classContent); } private static File addFileToProject(IPath targetPath, String fileName, String fileContent) throws CoreException, FileNotFoundException { IFileStore targetFileStore = EFS.getLocalFileSystem().fromLocalFile( targetPath.append(fileName).toFile()); File targetFile = targetFileStore.toLocalFile(EFS.NONE, null); targetFile.getParentFile().mkdirs(); PrintStream ps = new PrintStream(new FileOutputStream(targetFile)); ps.print(fileContent); ps.close(); return targetFile; } /** * This function overrides all the existing metadata for the project. */ public static void addLambdaProjectMetadata(IProject project, LambdaFunctionProjectMetadata metadata) { if (!metadata.isValid()) { throw new IllegalArgumentException( "Invalid Lambda project metadata."); } IPath settingsDir = getProjectDirectory(project, ".settings"); settingsDir.toFile().mkdirs(); File settingFile = settingsDir.append(LAMBDA_PROJECT_SETTING_FILE).toFile(); OutputStream out = null; try { out = new FileOutputStream(settingFile); metadata.toProperties().store(out, "Lambda Function Project Metadata"); } catch (Exception e) { LambdaPlugin.getDefault().reportException( "Failed to write project metadata.", e); } if (out != null) { try { out.close(); } catch (IOException e) { LambdaPlugin.getDefault().warn( "Failed to close FileOutputStreama " + "after writing project metadata.", e); } } } public static LambdaFunctionProjectMetadata loadLambdaProjectMetadata(IProject project) { IPath settingsDir = getProjectDirectory(project, ".settings"); File settingFile = settingsDir.append(LAMBDA_PROJECT_SETTING_FILE).toFile(); if (!settingFile.exists()) { return null; } InputStream in = null; Properties props = new Properties(); try { in = new FileInputStream(settingFile); props.load(in); } catch (Exception e) { LambdaPlugin.getDefault().reportException( "Failed to read project metadata.", e); } if (in != null) { try { in.close(); } catch (IOException e) { LambdaPlugin.getDefault().warn( "Failed to close FileInputStream " + "after reading project metadata.", e); } } return LambdaFunctionProjectMetadata.fromProperties(props); } private static IPath getProjectDirectory(IProject project, String path) { IPath workspaceRoot = project.getWorkspace().getRoot().getRawLocation(); IPath projectRoot = workspaceRoot.append(project.getFullPath()); if (path == null) { return projectRoot; } else { return projectRoot.append(path); } } public static void refreshProject(IProject project) { // Finally, refresh the project so that the new files show up try { project.refreshLocal(IResource.DEPTH_INFINITE, null); } catch (CoreException e) { LambdaPlugin.getDefault().warn( "Failed to refresh project " + project.getName(), e); } } }