Example usage for java.nio.charset MalformedInputException getMessage

List of usage examples for java.nio.charset MalformedInputException getMessage

Introduction

In this page you can find the example usage for java.nio.charset MalformedInputException getMessage.

Prototype

public String getMessage() 

Source Link

Document

Returns the message.

Usage

From source file:squash.deployment.lambdas.AngularjsAppCustomResourceLambda.java

/**
 * Implementation for the AWS Lambda function backing the AngularjsApp
 * resource.//  www . ja va  2s .  c  om
 * 
 * <p>
 * This lambda requires the following environment variables:
 * <ul>
 * <li>WebsiteBucket - name of S3 bucket serving the booking website.</li>
 * <li>AngularjsZipBucket - S3 bucket holding the Angularjs app zip file.</li>
 * <li>CognitoIdentityPoolId - id of the Cognito Identity Pool.</li>
 * <li>CognitoUserPoolId - id of the Cognito User Pool.</li>
 * <li>CognitoUserPoolIdentityProviderName - Name of user pool identity provider.</li>
 * <li>JavascriptClientAppId - id of the Cognito User Pool app to use from javascript.</li>
 * <li>ApiGatewayBaseUrl - base Url of the ApiGateway Api.</li>
 * <li>Region - the AWS region in which the Cloudformation stack is created.</li>
 * <li>Revision - integer incremented to force stack updates to update this resource.</li>
 * </ul>
 *
 * <p>On success, it returns the following output to Cloudformation:
 * <ul>
 *    <li>WebsiteURL - Url of the Angularjs website.</li>
 * </ul>
 *
 * <p>Updates will delete the previous deployment and replace it with the new one.
 *
 * @param request
 *            request parameters as provided by the CloudFormation service
 * @param context
 *            context as provided by the CloudFormation service
 */
@Override
public Object handleRequest(Map<String, Object> request, Context context) {

    LambdaLogger logger = context.getLogger();
    logger.log("Starting AngularjsApp custom resource handleRequest");

    // Handle standard request parameters
    Map<String, String> standardRequestParameters = LambdaInputLogger.logStandardRequestParameters(request,
            logger);
    String requestType = standardRequestParameters.get("RequestType");

    // Handle required environment variables
    logger.log("Logging required environment variables for custom resource request");
    String websiteBucket = System.getenv("WebsiteBucket");
    String angularjsZipBucket = System.getenv("AngularjsZipBucket");
    String cognitoIdentityPoolId = System.getenv("CognitoIdentityPoolId");
    String cognitoUserPoolId = System.getenv("CognitoUserPoolId");
    String cognitoUserPoolIdentityProviderName = System.getenv("CognitoUserPoolIdentityProviderName");
    String javascriptClientAppId = System.getenv("JavascriptClientAppId");
    String apiGatewayBaseUrl = System.getenv("ApiGatewayBaseUrl");
    String region = System.getenv("AWS_REGION");
    String revision = System.getenv("Revision");

    // Log out our required environment variables
    logger.log("WebsiteBucket: " + websiteBucket);
    logger.log("AngularjsZipBucket: " + angularjsZipBucket);
    logger.log("CognitoIdentityPoolId: " + cognitoIdentityPoolId);
    logger.log("CognitoUserPoolId: " + cognitoUserPoolId);
    logger.log("CognitoUserPoolIdentityProviderName: " + cognitoUserPoolIdentityProviderName);
    logger.log("JavascriptClientAppId: " + javascriptClientAppId);
    logger.log("ApiGatewayBaseUrl: " + apiGatewayBaseUrl);
    logger.log("Region: " + region);
    logger.log("Revision: " + revision);

    // API calls below can sometimes give access denied errors during stack
    // creation which I think is bc required new roles have not yet propagated
    // across AWS. We sleep here to allow time for this propagation.
    try {
        Thread.sleep(10000);
    } catch (InterruptedException e) {
        logger.log("Sleep to allow new roles to propagate has been interrupted.");
    }

    // Prepare our response to be sent in the finally block
    CloudFormationResponder cloudFormationResponder = new CloudFormationResponder(standardRequestParameters,
            "DummyPhysicalResourceId");
    // Initialise failure response, which will be changed on success
    String responseStatus = "FAILED";

    String websiteURL = null;
    try {
        cloudFormationResponder.initialise();

        if (requestType.equals("Create") || requestType.equals("Update")) {

            // On updates we clear out the app first
            if (requestType.equals("Update")) {
                deleteAngularjsApp(websiteBucket, logger);
            }

            // Get the Angularjs app's zip file
            try {
                logger.log("Downloading Angularjs zip from S3");
                IS3TransferManager transferManager = getS3TransferManager();
                String zipDownloadPath = "/tmp/AngularjsApp.zip";
                File downloadedFile = new File(zipDownloadPath);
                TransferUtils.waitForS3Transfer(
                        transferManager.download(angularjsZipBucket, "AngularjsApp.zip", downloadedFile),
                        logger);
                logger.log("Downloaded Angularjs zip successfully from S3");

                // Modify the Bookings and Identity Service files to point to the
                // correct Cognito data, ApiGateway base url, and region.
                logger.log("Extracting Angularjs zip");
                String extractPath = "/tmp";
                try {
                    ZipFile zipFile = new ZipFile(zipDownloadPath);
                    // Will produce /tmp/app/app.js etc
                    zipFile.extractAll(extractPath);
                } catch (ZipException e) {
                    logger.log("Caught a ZipException Exception: " + e.getMessage());
                    throw e;
                }
                logger.log("Extracted Angularjs zip");

                logger.log(
                        "Modifying the Bookings and Identity Services to point to the correct ApiGatewayBaseUrl, Cognito data, and region");
                String fileContent;
                String filePath = extractPath + "/app/sqawsh.min.js";
                try (FileInputStream inputStream = new FileInputStream(filePath)) {
                    fileContent = IOUtils.toString(inputStream);
                }
                fileContent = fileContent.replace("bookingregiontobereplaced", region)
                        .replace("bookingurltobereplaced", apiGatewayBaseUrl)
                        .replace("bookingbuckettobereplaced", websiteBucket)
                        .replace("identityregiontobereplaced", region)
                        .replace("identitypoolidtobereplaced", cognitoIdentityPoolId)
                        .replace("identityuserpoolidtobereplaced", cognitoUserPoolId)
                        .replace("identityprovidernametobereplaced", cognitoUserPoolIdentityProviderName)
                        .replace("identityappidtobereplaced", javascriptClientAppId);

                FileUtils.writeStringToFile(new File(filePath), fileContent);
                logger.log(
                        "Modified the Bookings and Identity Services to point to the correct ApiGatewayBaseUrl, Cognito data, and region");

                // We will later modify the gzip-ed filenames to add a revving suffix.
                // But before we gzip, we need to modify the revved file links in
                // index.html
                String revvingSuffix = System.getenv("RevvingSuffix");
                File appPath = new File("/tmp/app");
                logger.log("Modifying links to revved files in index.html");
                Path indexPath = new File(appPath, "index.html").toPath();
                Charset charset = StandardCharsets.UTF_8;
                List<String> newLines = new ArrayList<>();
                for (String line : Files.readAllLines(indexPath, charset)) {
                    if (line.contains("googleapis") || line.contains("cloudflare") || line.contains("maxcdn")) {
                        // Don't alter lines linking to cdn-s. They are already revved.
                        newLines.add(line);
                    } else {
                        newLines.add(line.replace(".js", "_" + revvingSuffix + ".js").replace(".css",
                                "_" + revvingSuffix + ".css"));
                    }
                }
                Files.write(indexPath, newLines, charset);
                logger.log("Modified links to revved files in index.html");

                // GZIP all js, css, and html files within app folder
                logger.log("GZip-ing files in app folder to enable serving gzip-ed from S3");
                squash.deployment.lambdas.utils.FileUtils.gzip(Arrays.asList(appPath), Collections.emptyList(),
                        logger);
                logger.log("GZip-ed files in app folder to enable serving gzip-ed from S3");

                // Rev the js and css files by appending revving-suffix to names - for
                // cache-ing
                logger.log("Appending revving suffix to js and css files in app folder");
                squash.deployment.lambdas.utils.FileUtils.appendRevvingSuffix(revvingSuffix, appPath.toPath(),
                        logger);
                logger.log("Appended revving suffix to js and css files in app folder");

                // Upload the modified app to the S3 website bucket
                logger.log("Uploading modified Angularjs app to S3 website bucket");
                // Will produce <S3BucketRoot>/app/sqawsh.min.js etc
                TransferUtils.waitForS3Transfer(transferManager.uploadDirectory(websiteBucket, "app",
                        new File(extractPath + "/app"), true), logger);
                logger.log("Uploaded modified Angularjs app to S3 website bucket");

                // Add gzip content-encoding metadata to zip-ed files
                logger.log("Updating metadata on modified Angularjs app in S3 bucket");
                TransferUtils.addGzipContentEncodingMetadata(websiteBucket, Optional.of("app"), logger);
                logger.log("Updated metadata on modified Angularjs app in S3 bucket");

                // Upload Cognito SDKs and their dependencies - these should all be
                // zipped first. N.B. We also append filenames with the revving
                // suffix.
                logger.log("About to upload Cognito libraries");
                List<ImmutableTriple<String, String, byte[]>> cognitoLibraries = new ArrayList<>();
                cognitoLibraries.add(new ImmutableTriple<>("Cognito SDK",
                        "aws-cognito-sdk.min_" + revvingSuffix + ".js", IOUtils.toByteArray(new URL(
                                "https://raw.githubusercontent.com/aws/amazon-cognito-identity-js/master/dist/aws-cognito-sdk.min.js"))));
                cognitoLibraries.add(new ImmutableTriple<>("Cognito Identity SDK",
                        "amazon-cognito-identity.min_" + revvingSuffix + ".js", IOUtils.toByteArray(new URL(
                                "https://raw.githubusercontent.com/aws/amazon-cognito-identity-js/master/dist/amazon-cognito-identity.min.js"))));
                cognitoLibraries.add(new ImmutableTriple<>("Big Integer Library",
                        "jsbn_" + revvingSuffix + ".js",
                        IOUtils.toByteArray(new URL("http://www-cs-students.stanford.edu/~tjw/jsbn/jsbn.js"))));
                cognitoLibraries.add(new ImmutableTriple<>("Big Integer Library 2",
                        "jsbn2_" + revvingSuffix + ".js", IOUtils.toByteArray(
                                new URL("http://www-cs-students.stanford.edu/~tjw/jsbn/jsbn2.js"))));

                // The SJCL still seems to need configuring to include the bytes
                // codec, despite 1.0 of Cognito Idp saying it had removed this
                // dependency. So for now we get this bytes-codec-configured version
                // from our resources.
                String sjcl_library;
                try {
                    sjcl_library = IOUtils.toString(AngularjsAppCustomResourceLambda.class
                            .getResourceAsStream("/squash/deployment/lambdas/sjcl.js"));
                } catch (IOException e) {
                    logger.log("Exception caught reading sjcl.js file: " + e.getMessage());
                    throw new Exception("Exception caught reading sjcl.js file");
                }
                logger.log("Read modified SJCL library from resources");
                cognitoLibraries.add(new ImmutableTriple<>("Stanford Javascript Crypto Library",
                        "sjcl_" + revvingSuffix + ".js", sjcl_library.getBytes(Charset.forName("UTF-8"))));

                for (ImmutableTriple<String, String, byte[]> cognitoLibrary : cognitoLibraries) {
                    logger.log("Uploading a Cognito library to S3 website bucket. Library name: "
                            + cognitoLibrary.left);

                    byte[] zippedLibrary = squash.deployment.lambdas.utils.FileUtils.gzip(cognitoLibrary.right,
                            logger);
                    ByteArrayInputStream libraryAsGzippedStream = new ByteArrayInputStream(zippedLibrary);
                    ObjectMetadata metadata = new ObjectMetadata();
                    metadata.setContentLength(zippedLibrary.length);
                    metadata.setContentEncoding("gzip");
                    String keyName = "app/components/identity/cognito/" + cognitoLibrary.middle;
                    logger.log("Uploading to key: " + keyName);
                    PutObjectRequest putObjectRequest = new PutObjectRequest(websiteBucket, keyName,
                            libraryAsGzippedStream, metadata);
                    TransferUtils.waitForS3Transfer(transferManager.upload(putObjectRequest), logger);
                    logger.log("Uploaded a Cognito library to S3 website bucket: " + cognitoLibrary.left);
                }

                // Add cache-control metadata to files. Css and js files will have
                // 1-year cache validity, since they are rev-ved.
                logger.log("Updating cache-control metadata on angular app in S3 bucket");
                TransferUtils.addCacheControlHeader("max-age=31536000", websiteBucket, Optional.of("app"),
                        ".js", logger);
                TransferUtils.addCacheControlHeader("max-age=31536000", websiteBucket, Optional.of("app"),
                        ".css", logger);
                // All html must revalidate every time
                TransferUtils.addCacheControlHeader("no-cache, must-revalidate", websiteBucket,
                        Optional.of("app"), ".html", logger);
                logger.log("Updated cache-control metadata on angular app in S3 bucket");

                // App content must be public so it can be served from the website
                logger.log("Modifying Angularjs app ACL in S3 website bucket");
                TransferUtils.setPublicReadPermissionsOnBucket(websiteBucket, Optional.of("app/"), logger);
                logger.log("Modified Angularjs app ACL in S3 website bucket");

            } catch (MalformedInputException mie) {
                logger.log("Caught a MalformedInputException: " + mie.getMessage());
                throw mie;
            } catch (IOException ioe) {
                logger.log("Caught an IO Exception: " + ioe.getMessage());
                throw ioe;
            }

            websiteURL = "http://" + websiteBucket + ".s3-website-" + region + ".amazonaws.com/app/index.html";
            ;
        } else if (requestType.equals("Delete")) {
            logger.log("Delete request - so deleting the app");
            deleteAngularjsApp(websiteBucket, logger);
        }

        responseStatus = "SUCCESS";
        return null;
    } catch (AmazonServiceException ase) {
        ExceptionUtils.logAmazonServiceException(ase, logger);
        return null;
    } catch (AmazonClientException ace) {
        ExceptionUtils.logAmazonClientException(ace, logger);
        return null;
    } catch (Exception e) {
        logger.log("Exception caught in AngularjsApp Lambda: " + e.getMessage());
        return null;
    } finally {
        // Send response to CloudFormation
        cloudFormationResponder.addKeyValueOutputsPair("WebsiteURL", websiteURL);
        cloudFormationResponder.sendResponse(responseStatus, logger);
    }
}