io.klerch.alexa.tellask.util.resource.ResourceUtteranceReader 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.util.resource;
import io.klerch.alexa.tellask.schema.UtteranceReader;
import org.apache.commons.lang3.Validate;
import java.io.InputStream;
import java.net.URL;
/**
* An implementation to the UtteranceReader interface which encapsulates
* logic of reading out a set of utterances from the the class-loader. Thus
* it expects YAML files (utterances.yml) in the resources-directory of your
* skill project. It looks for this YAML file in directories whose name equals the locale coming in
* from the speechlet request (e.g. /en-US/utterances.yml). You could provide
* a leading path over the constructor to have your files stored like e.g.
* /my/leading/path/en-US/utterances.yml). In addition by overriding the resourceLocation
* you could add some trailing path to have something like this
* /my/leading/path/en-US/my/trailing/path/utterances.yml
* That said it is possible to provide utterances for different locales just
* by having those files in the right place.
*/
public class ResourceUtteranceReader implements UtteranceReader {
/**
* The default resource location. This is just the trailing portion of
* the qualified resource path.
*/
public static final String DEFAULT_RESOURCE_LOCATION = "/utterances.yml";
/**
* The default leading path. This is the portion in front of the locale
* folder.
*/
public static final String DEFAULT_LEADING_PATH = "/";
private final String leadingPath;
private String resourceLocation = DEFAULT_RESOURCE_LOCATION;
/**
* New reader for classloader-resources. Note that a
* fully qualified path is a concatenation of the leading path (set in the constructor),
* the locale (given to the read-method) and the trailing resource location containing the actual filename (can be overridden
* by setting resourceLocation or providing the the constructor as well).
* You may end up with something like /my/leading/path/en-US/my/trailing/path/utterances.yml
* where "en-US" is the only portion you cannot influence as it comes with the locale of
* a speechlet request.
*/
public ResourceUtteranceReader() {
this(DEFAULT_LEADING_PATH, DEFAULT_RESOURCE_LOCATION);
}
/**
* New reader for classloader-resources giving it a valid leading path. Note that a
* fully qualified path is a concatenation of the leading path (set in the constructor),
* the locale (given to the read-method) and the trailing resource location containing the actual filename (can be overridden
* by setting resourceLocation or providing the the constructor as well).
* You may end up with something like /my/leading/path/en-US/my/trailing/path/utterances.yml
* where "en-US" is the only portion you cannot influence as it comes with the locale of
* a speechlet request.
* @param leadingPath leading path to the actual resource (YAML) file
*/
public ResourceUtteranceReader(final String leadingPath) {
this(leadingPath, DEFAULT_RESOURCE_LOCATION);
}
/**
* New reader for classloader-resources giving it a valid leading path. Note that a
* fully qualified path is a concatenation of the leading path (set in the constructor),
* the locale (given to the read-method) and the trailing resource location containing the actual filename (can be overridden
* by setting resourceLocation or providing the the constructor as well).
* You may end up with something like /my/leading/path/en-US/my/trailing/path/utterances.yml
* where "en-US" is the only portion you cannot influence as it comes with the locale of
* a speechlet request.
* @param leadingPath leading path to the actual resource (YAML) file
* @param resourceLocation the resource location. must end with ".yml"
*/
public ResourceUtteranceReader(final String leadingPath, final String resourceLocation) {
setResourceLocation(resourceLocation);
final StringBuilder sb = new StringBuilder();
sb.append(leadingPath.startsWith("/") ? leadingPath.substring(1) : leadingPath);
if (!leadingPath.endsWith("/"))
sb.append("/");
this.leadingPath = sb.toString();
}
/**
* {@inheritDoc}
*/
@Override
public String getLeadingPath() {
return leadingPath;
}
/**
* {@inheritDoc}
*/
@Override
public String getResourceLocation() {
return this.resourceLocation;
}
/**
* {@inheritDoc}
*/
@Override
public void setResourceLocation(final String resourceLocation) {
Validate.notBlank(resourceLocation, "No resource location is set to read from.");
Validate.notBlank(resourceLocation.replace("/", ""), "No resource location is set to read from.");
Validate.isTrue(resourceLocation.endsWith(".yml"), "Resource location must end with .yml");
this.resourceLocation = resourceLocation.startsWith("/") ? resourceLocation : "/" + resourceLocation;
}
/**
* {@inheritDoc}
*/
@Override
public ResourceUtteranceReader fromResourceLocation(final String resourceLocation) {
setResourceLocation(resourceLocation);
return this;
}
/**
* {@inheritDoc}
*/
@Override
public InputStream read(final String locale) {
Validate.notNull(locale, "Locale must not be blank.");
final String resourcePath = leadingPath + locale + resourceLocation;
final String resourcePath2 = resourcePath.startsWith("/") ? resourcePath.substring(1) : resourcePath;
final ClassLoader cl = getClass().getClassLoader();
Validate.notNull(cl.getResource(resourcePath2), "Resource " + resourcePath2 + " does not exist in current context.");
return cl.getResourceAsStream(resourcePath2);
}
}