io.klerch.alexa.tellask.model.wrapper.AlexaSpeechletServlet Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of alexa-skills-kit-tellask-java Show documentation
Show all versions of alexa-skills-kit-tellask-java Show documentation
This SDK is an extension to the Alexa Skills SDK for Java. It provides a framework for handling speechlet requests with multi-variant utterances organized in YAML files that make it easy to create localized skills. This SDK also lets you build your skill in declarative style and avoids a lot of boilerplate code.
/**
* 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 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 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);
}
}