io.klerch.alexa.tellask.model.wrapper.AlexaSpeechletServlet.java Source code

Java tutorial

Introduction

Here is the source code for io.klerch.alexa.tellask.model.wrapper.AlexaSpeechletServlet.java

Source

/**
 * Created by Kay Lerch (https://twitter.com/KayLerch)
 *
 * Contribute to https://github.com/KayLerch/alexa-skills-kit-tellask-java
 *
 * Attached license applies.
 * This source is licensed under GNU GENERAL PUBLIC LICENSE Version 3 as of 29 June 2007
 */
package io.klerch.alexa.tellask.model.wrapper;

import com.amazon.speech.Sdk;
import com.amazon.speech.speechlet.Speechlet;
import com.amazon.speech.speechlet.servlet.SpeechletServlet;
import io.klerch.alexa.state.handler.AlexaStateHandler;
import io.klerch.alexa.tellask.schema.UtteranceReader;
import io.klerch.alexa.tellask.schema.annotation.AlexaApplication;
import io.klerch.alexa.tellask.util.factory.AlexaSpeechletFactory;
import io.klerch.alexa.tellask.util.resource.ResourceUtteranceReader;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.Validate;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * A servlet extending the SpeechletServlet to comply with Tellask SDK.
 * You can provide supported application-ids and your own AlexaSpeechlet
 * by using AlexaApplication annotation or by overriding the corresponding
 * getters
 */
public abstract class AlexaSpeechletServlet extends SpeechletServlet {
    /**
     * When this servlet is created it obtains supported application ids from overridden getter
     * or AlexaApplication-annotation and joins this set of ids with supported application ids
     * configured in system property 'com.amazon.speech.speechlet.servlet.supportedApplicationIds'
     */
    public AlexaSpeechletServlet() {
        super();

        final Set<String> customSupportedApplicationIds = getSupportedApplicationIds();

        if (!customSupportedApplicationIds.isEmpty()) {
            // add supported application ids to system variable
            final String systemSupportedApplicationIds = System
                    .getProperty(Sdk.SUPPORTED_APPLICATION_IDS_SYSTEM_PROPERTY);

            if (systemSupportedApplicationIds != null) {
                customSupportedApplicationIds.addAll(Arrays.asList(systemSupportedApplicationIds.split(",")));
            }
            // update system property with appended application ids provided by this servlet
            System.setProperty(Sdk.SUPPORTED_APPLICATION_IDS_SYSTEM_PROPERTY,
                    String.join(",", customSupportedApplicationIds));
        }
    }

    /**
     * Provides a set of application-id(s) you can find in the Alexa developer console of your skill.
     * Only requests coming in with these application-id(s) pass the request verification.
     * @return supported application ids
     */
    public Set<String> getSupportedApplicationIds() {
        final AlexaApplication app = this.getClass().getAnnotation(AlexaApplication.class);
        return app != null ? Stream.of(app.applicationIds()).collect(Collectors.toSet()) : Collections.emptySet();
    }

    /**
     * Provides the speechlet used to handle the request.
     * @return speechlet used to handle the request.
     */
    public Class<? extends AlexaSpeechlet> getAlexaSpeechlet() {
        final AlexaApplication app = this.getClass().getAnnotation(AlexaApplication.class);
        return app != null ? app.speechlet() : AlexaSpeechlet.class;
    }

    /**
     * Override this method to return a customized utterance-reader. This gives
     * you freedom of storing your utterance YAML files at any location you desire.
     * If you want to decide how to configure an utterance reader individually you
     * can set it inside your request handlers by giving it to AlexaOutput. That said
     * the value you set right here could be overridden.
     * @return customized utterance reader
     */
    public UtteranceReader getUtteranceReader() {
        return new ResourceUtteranceReader();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final Speechlet getSpeechlet() {
        return super.getSpeechlet();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final void setSpeechlet(final Speechlet speechlet) {
        // enforce speechlet which extends AlexaSpeechlet
        Validate.isInstanceOf(AlexaSpeechlet.class, speechlet,
                "Servlet expects a speechlet extending AlexaSpeechlet.");
        super.setSpeechlet(speechlet);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void doPost(final HttpServletRequest request, final HttpServletResponse response) throws IOException {
        // wrap servlet request as we need to read from it before it is read a second time in super doPost
        final AlexaHttpServletRequest wrapper = new AlexaHttpServletRequest(request);
        // intervene post to extract locale but also to override the speechlet
        byte[] serializedSpeechletRequest = IOUtils.toByteArray(wrapper.getInputStream());
        final AlexaSpeechlet speechlet = AlexaSpeechletFactory
                .createSpeechletFromRequest(serializedSpeechletRequest, getAlexaSpeechlet(), getUtteranceReader());
        // override speechlet with AlexaSpeechlet
        setSpeechlet(speechlet);
        super.doPost(wrapper, response);
    }
}