I'm implementing Alexa Skills logic (speechlets) using Java Alexa Skills Kit SDK hosted on Apache Tomcat. However, I need to move the project to Apache Sling based server. It's based on OSGi container (Apache Felix). I found Sling DI mechanisms very useful. However it looks like Java Alexa Skills Kit SDK is totally not prepared for such an use. The main problem is that the SDK servlet is a plain Java servlet and Sling doesn't support it. Moreover the SDK is not even an OSGi bundle. It would be nice to use it in Sling style, but I don't want to replicate the SDK from scratch.
Did anyone create Skills as a Sling services in OSGi container? Do I have to create a SlingServlet on my own? Can Java Alexa Skills Kit SDK work with Sling services?
You are right that Java Alexa Skills Kit SDK is not OSGi enabled and the servlet doesn't work with Sling. However, rest of the API (apart from the servlet) consists of plain Java objects so it's possible to use it with Sling. This is the reason why I created alexa-skills-sling library which wraps the Java Alexa Skills Kit SDK into Sling features so you can use services and DI mechanisms.
To use it you need to add a dependency:
<dependency>
<groupId>eu.zacheusz.sling.alexa</groupId>
<artifactId>alexa-skills-sling</artifactId>
<version>1.2.1</version>
</dependency>
and install it as OSGi bundle. For example:
<plugins>
<plugin>
<groupId>org.apache.sling</groupId>
<artifactId>maven-sling-plugin</artifactId>
<executions>
<execution>
<id>install-dependency</id>
<goals>
<goal>install-file</goal>
</goals>
<phase>install</phase>
<configuration>
<!-- install dependency to test AEM Server -->
<slingUrl>http://${vm.host}:${vm.port}/apps/alexa/install</slingUrl>
<deploymentMethod>WebDAV</deploymentMethod>
<user>${vm.username}</user>
<password>${vm.password}</password>
<groupId>eu.zacheusz.sling.alexa</groupId>
<artifactId>alexa-skills-sling</artifactId>
<version>${alexa-skills-sling.version}</version>
<packaging>jar</packaging>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
Then to implement a single intent logic just add sling annotations to the implementation and it will be picked up by the library.
@Component
@Service(IntentHandler.class)
Here is a very basic example of Intent logic implementation and you can find more examples in this project:
@Component
@Service(IntentHandler.class)
public class ExampleSimpleIntentHandlerService implements IntentHandler {
private static final String SLOT_NAME = "mySlot";
private static final String INTENT_NAME = "myIntent";
@Override
public boolean supportsIntent(String intentName) {
return INTENT_NAME.equals(intentName);
}
@Override
public SpeechletResponse handleIntent(final SpeechletRequestEnvelope<IntentRequest> requestEnvelope) {
final IntentRequest request = requestEnvelope.getRequest();
final Intent intent = request.getIntent();
final Slot slot = intent.getSlot(SLOT_NAME);
final String responseMessage;
if (slot == null) {
responseMessage = format(
"I got your request, but there is no slot %",
SLOT_NAME);
} else {
responseMessage = format(
"I got your request. Slot value is %s. Thanks!",
slot.getValue());
}
return newTellResponse(responseMessage);
}
private SpeechletResponse newTellResponse(final String text) {
return SpeechletResponse.newTellResponse(newPlainTextOutputSpeech(text));
}
private PlainTextOutputSpeech newPlainTextOutputSpeech(final String text) {
final PlainTextOutputSpeech speech = new PlainTextOutputSpeech();
speech.setText(text);
return speech;
}
}