Skip to content

Commit

Permalink
Introduce module component for SDK extensions
Browse files Browse the repository at this point in the history
  • Loading branch information
breedloj authored and sungolivia committed Jun 14, 2018
1 parent 649ca7d commit 3566f16
Show file tree
Hide file tree
Showing 11 changed files with 401 additions and 99 deletions.
32 changes: 3 additions & 29 deletions ask-sdk-core/src/com/amazon/ask/builder/CustomSkillBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,36 +13,10 @@

package com.amazon.ask.builder;

import com.amazon.ask.model.services.ApiClient;
import com.amazon.ask.Skill;
import com.amazon.ask.attributes.persistence.PersistenceAdapter;

/**
* Builder used to construct a new {@link Skill} with a custom {@link ApiClient} and {@link PersistenceAdapter}.
* Builder used to construct a new {@link Skill} without any additional modules.
* Direct passthrough to {@link SkillBuilder}.
*/
public class CustomSkillBuilder extends SkillBuilder<CustomSkillBuilder> {

protected PersistenceAdapter persistenceAdapter;
protected ApiClient apiClient;

public CustomSkillBuilder withPersistenceAdapter(PersistenceAdapter persistenceAdapter) {
this.persistenceAdapter = persistenceAdapter;
return this;
}

public CustomSkillBuilder withApiClient(ApiClient apiClient) {
this.apiClient = apiClient;
return this;
}

protected SkillConfiguration.Builder getConfigBuilder() {
return super.getConfigBuilder()
.withPersistenceAdapter(persistenceAdapter)
.withApiClient(apiClient);
}

public Skill build() {
return new Skill(getConfigBuilder().build());
}

}
public class CustomSkillBuilder extends SkillBuilder<CustomSkillBuilder> {}
81 changes: 58 additions & 23 deletions ask-sdk-core/src/com/amazon/ask/builder/SkillBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,37 +14,42 @@
package com.amazon.ask.builder;

import com.amazon.ask.Skill;
import com.amazon.ask.attributes.persistence.PersistenceAdapter;
import com.amazon.ask.dispatcher.exception.ExceptionHandler;
import com.amazon.ask.dispatcher.exception.ExceptionMapper;
import com.amazon.ask.dispatcher.exception.impl.DefaultExceptionMapper;
import com.amazon.ask.dispatcher.request.interceptor.RequestInterceptor;
import com.amazon.ask.dispatcher.request.interceptor.ResponseInterceptor;
import com.amazon.ask.dispatcher.request.handler.RequestHandler;
import com.amazon.ask.dispatcher.request.mapper.RequestMapper;
import com.amazon.ask.dispatcher.request.handler.impl.DefaultHandlerAdapter;
import com.amazon.ask.dispatcher.request.handler.impl.DefaultRequestHandlerChain;
import com.amazon.ask.dispatcher.request.mapper.impl.DefaultRequestMapper;
import com.amazon.ask.model.services.ApiClient;
import com.amazon.ask.module.SdkModuleContext;
import com.amazon.ask.module.SdkModule;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

public abstract class SkillBuilder<T extends SkillBuilder<T>> {
public class SkillBuilder<T extends SkillBuilder<T>> {

protected final List<RequestHandler> requestHandlers;
protected final List<ExceptionHandler> exceptionHandlers;
protected final List<RequestInterceptor> requestInterceptors;
protected final List<ResponseInterceptor> responseInterceptors;

protected final List<SdkModule> sdkModules;
protected PersistenceAdapter persistenceAdapter;
protected ApiClient apiClient;
protected String skillId;

public SkillBuilder() {
this.requestHandlers = new ArrayList<>();
this.exceptionHandlers = new ArrayList<>();
this.requestInterceptors = new ArrayList<>();
this.responseInterceptors = new ArrayList<>();
this.sdkModules = new ArrayList<>();
}

public T addRequestHandler(RequestHandler handler) {
Expand Down Expand Up @@ -107,6 +112,21 @@ public T addExceptionHandlers(ExceptionHandler... handler) {
return getThis();
}

public T withPersistenceAdapter(PersistenceAdapter persistenceAdapter) {
this.persistenceAdapter = persistenceAdapter;
return getThis();
}

public T withApiClient(ApiClient apiClient) {
this.apiClient = apiClient;
return getThis();
}

public T registerSdkModule(SdkModule sdkModule) {
sdkModules.add(sdkModule);
return getThis();
}

public T withSkillId(String skillId) {
this.skillId = skillId;
return getThis();
Expand All @@ -118,28 +138,43 @@ private T getThis() {
}

protected SkillConfiguration.Builder getConfigBuilder() {
List<DefaultRequestHandlerChain> requestHandlerChains = requestHandlers.stream()
.map(handler -> DefaultRequestHandlerChain.builder()
.withRequestHandler(handler).build())
.collect(Collectors.toList());

RequestMapper mapper = DefaultRequestMapper.builder()
.withRequestHandlerChains(requestHandlerChains)
.build();

ExceptionMapper exceptionMapper = DefaultExceptionMapper.builder()
.withExceptionHandlers(exceptionHandlers)
.build();

return SkillConfiguration.builder()
.withRequestMappers(Collections.singletonList(mapper))
.withHandlerAdapters(Collections.singletonList(new DefaultHandlerAdapter()))
.withExceptionMapper(exceptionMapper)
.withRequestInterceptors(requestInterceptors)
SkillConfiguration.Builder skillConfigBuilder = SkillConfiguration.builder();

if (!requestHandlers.isEmpty()) {
List<DefaultRequestHandlerChain> requestHandlerChains = requestHandlers.stream()
.map(handler -> DefaultRequestHandlerChain.builder()
.withRequestHandler(handler).build())
.collect(Collectors.toList());

skillConfigBuilder.addRequestMapper(DefaultRequestMapper.builder()
.withRequestHandlerChains(requestHandlerChains)
.build())
.addHandlerAdapter(new DefaultHandlerAdapter());
}

if (!exceptionHandlers.isEmpty()) {
ExceptionMapper exceptionMapper = DefaultExceptionMapper.builder()
.withExceptionHandlers(exceptionHandlers)
.build();
skillConfigBuilder.withExceptionMapper(exceptionMapper);
}

skillConfigBuilder.withRequestInterceptors(requestInterceptors)
.withResponseInterceptors(responseInterceptors)
.withPersistenceAdapter(persistenceAdapter)
.withApiClient(apiClient)
.withSkillId(skillId);

SdkModuleContext sdkModuleContext = new SdkModuleContext(skillConfigBuilder);
for (SdkModule sdkModule : sdkModules) {
sdkModule.setupModule(sdkModuleContext);
}

return skillConfigBuilder;
}

public abstract Skill build();
public Skill build() {
return new Skill(getConfigBuilder().build());
}

}
70 changes: 70 additions & 0 deletions ask-sdk-core/src/com/amazon/ask/builder/SkillConfiguration.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.amazon.ask.dispatcher.request.handler.HandlerAdapter;
import com.amazon.ask.dispatcher.request.mapper.RequestMapper;

import java.util.ArrayList;
import java.util.List;

/**
Expand Down Expand Up @@ -105,31 +106,83 @@ public static final class Builder {
private Builder() {
}

public Builder addRequestMapper(RequestMapper requestMapper) {
if (requestMappers == null) {
requestMappers = new ArrayList<>();
}
requestMappers.add(requestMapper);
return this;
}

public Builder withRequestMappers(List<RequestMapper> requestMappers) {
this.requestMappers = requestMappers;
return this;
}

public List<RequestMapper> getRequestMappers() {
return requestMappers;
}

public Builder addHandlerAdapter(HandlerAdapter handlerAdapter) {
if (handlerAdapters == null) {
handlerAdapters = new ArrayList<>();
}
handlerAdapters.add(handlerAdapter);
return this;
}

public Builder withHandlerAdapters(List<HandlerAdapter> handlerAdapters) {
this.handlerAdapters = handlerAdapters;
return this;
}

public List<HandlerAdapter> getHandlerAdapters() {
return handlerAdapters;
}

public Builder addRequestInterceptor(RequestInterceptor requestInterceptor) {
if (requestInterceptors == null) {
requestInterceptors = new ArrayList<>();
}
requestInterceptors.add(requestInterceptor);
return this;
}

public Builder withRequestInterceptors(List<RequestInterceptor> requestInterceptors) {
this.requestInterceptors = requestInterceptors;
return this;
}

public List<RequestInterceptor> getRequestInterceptors() {
return requestInterceptors;
}

public Builder addResponseInterceptor(ResponseInterceptor responseInterceptor) {
if (responseInterceptors == null) {
this.responseInterceptors = new ArrayList<>();
}
responseInterceptors.add(responseInterceptor);
return this;
}

public Builder withResponseInterceptors(List<ResponseInterceptor> responseInterceptors) {
this.responseInterceptors = responseInterceptors;
return this;
}

public List<ResponseInterceptor> getResponseInterceptors() {
return responseInterceptors;
}

public Builder withExceptionMapper(ExceptionMapper exceptionMapper) {
this.exceptionMapper = exceptionMapper;
return this;
}

public ExceptionMapper getExceptionMapper() {
return exceptionMapper;
}

public Builder withPersistenceAdapter(PersistenceAdapter persistenceAdapter) {
this.persistenceAdapter = persistenceAdapter;
return this;
Expand All @@ -140,19 +193,36 @@ public Builder withApiClient(ApiClient apiClient) {
return this;
}

public ApiClient getApiClient() {
return apiClient;
}

public Builder withCustomUserAgent(String customUserAgent) {
this.customUserAgent = customUserAgent;
return this;
}

public String getCustomUserAgent() {
return customUserAgent;
}

public Builder withSkillId(String skillId) {
this.skillId = skillId;
return this;
}

public String getSkillId() {
return skillId;
}

public SkillConfiguration build() {
return new SkillConfiguration(requestMappers, handlerAdapters, requestInterceptors, responseInterceptors,
exceptionMapper, persistenceAdapter, apiClient, customUserAgent, skillId);
}

public PersistenceAdapter getPersistenceAdapter() {
return persistenceAdapter;
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ protected DefaultRequestDispatcher(Collection<HandlerAdapter> handlerAdapters, C
Collection<RequestInterceptor> requestInterceptors, Collection<ResponseInterceptor> responseInterceptors) {
this.handlerAdapters = ValidationUtils.assertNotNull(handlerAdapters, "handlerAdapters");
this.requestMappers = ValidationUtils.assertNotEmpty(requestMappers, "requestMappers");
this.exceptionMapper = ValidationUtils.assertNotNull(exceptionMapper, "exceptionMapper");
this.exceptionMapper = exceptionMapper;
this.requestInterceptors = requestInterceptors != null ? requestInterceptors : new ArrayList<>();
this.responseInterceptors = responseInterceptors != null ? responseInterceptors : new ArrayList<>();
}
Expand All @@ -76,7 +76,8 @@ public Optional<Response> dispatch(HandlerInput input) throws AskSdkException {
try {
return doDispatch(input);
} catch (Exception e) {
Optional<ExceptionHandler> exceptionHandler = exceptionMapper.getHandler(input, e);
Optional<ExceptionHandler> exceptionHandler = exceptionMapper != null
? exceptionMapper.getHandler(input, e) : Optional.empty();
if (exceptionHandler.isPresent()) {
logger.debug("[{}] Found suitable exception handler", requestId);
return exceptionHandler.get().handle(input, e);
Expand Down
32 changes: 32 additions & 0 deletions ask-sdk-core/src/com/amazon/ask/module/SdkModule.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file
except in compliance with the License. A copy of the License is located at
http://aws.amazon.com/apache2.0/
or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for
the specific language governing permissions and limitations under the License.
*/

package com.amazon.ask.module;

import com.amazon.ask.Skill;
import com.amazon.ask.builder.SkillBuilder;
import com.amazon.ask.builder.SkillConfiguration;

/**
* An interface for SDK extensions that can be registered on the {@link SkillBuilder} when setting up
* a {@link Skill} instance.
*/
public interface SdkModule {

/**
* Method called by the {@link SkillBuilder} when .build() is called. Allows this module to configure
* itself as part of {@link SkillConfiguration} building.
*/
void setupModule(SdkModuleContext context);

}
Loading

0 comments on commit 3566f16

Please sign in to comment.