package com.rayo.server.verb; import java.util.List; import javax.validation.ConstraintValidatorContext; import com.rayo.server.exception.ExceptionMapper; import com.rayo.server.validation.SsmlValidator; import com.rayo.core.validation.ValidationException; import com.rayo.core.verb.Ask; import com.rayo.core.verb.AskCompleteEvent; import com.rayo.core.verb.AskCompleteEvent.Reason; import com.rayo.core.verb.Choices; import com.rayo.core.verb.Ssml; import com.rayo.core.verb.VerbCompleteEvent; import com.voxeo.logging.Loggerf; import com.voxeo.moho.Participant; import com.voxeo.moho.State; import com.voxeo.moho.event.InputCompleteEvent; import com.voxeo.moho.media.Prompt; import com.voxeo.moho.media.input.Grammar; import com.voxeo.moho.media.input.InputCommand; import com.voxeo.moho.media.output.OutputCommand; import com.voxeo.moho.media.output.OutputCommand.BargeinType; import com.voxeo.servlet.xmpp.StanzaError; public class AskHandler extends AbstractLocalVerbHandler<Ask,Participant> { private Prompt<Participant> prompt; private SsmlValidator ssmlValidator; private static final Loggerf logger = Loggerf.getLogger(AskHandler.class); @Override public void start() { OutputCommand outCommand = null; Ssml ssml = model.getPrompt(); if (ssml != null) { outCommand = new OutputCommand(resolveAudio(ssml)); outCommand.setBargeinType(model.isBargein() ? BargeinType.ANY : BargeinType.NONE); outCommand.setVoiceName(model.getVoice()); } final List<Choices> choicesList = model.getChoices(); Grammar[] grammars = new Grammar[choicesList.size()]; for(int i=0; i<grammars.length; i++) { Choices choices = choicesList.get(i); Grammar grammar = null; if(choices.getUri() != null) { grammar = new Grammar(choices.getUri()); } else { grammar = new Grammar(choices.getContentType(), choices.getContent()); } grammars[i] = grammar; } InputCommand inputCommand = new InputCommand(grammars); long timeout = model.getTimeout().getMillis(); inputCommand.setInitialTimeout(timeout); inputCommand.setInterDigitsTimeout(timeout); inputCommand.setRecognizer(model.getRecognizer()); inputCommand.setInputMode(getMohoMode(model.getMode())); inputCommand.setTerminator(model.getTerminator()); inputCommand.setMinConfidence(model.getMinConfidence()); prompt = getMediaService().prompt(outCommand, inputCommand, 0); } @Override public boolean isStateValid(ConstraintValidatorContext context) { if (!isReady(participant)) { context.buildConstraintViolationWithTemplate("Call is not ready yet.") .addNode(ExceptionMapper.toString(StanzaError.Condition.RESOURCE_CONSTRAINT)) .addConstraintViolation(); return false; } if (isOnHold(participant)) { context.buildConstraintViolationWithTemplate( "Call is currently on hold.") .addNode(ExceptionMapper.toString(StanzaError.Condition.RESOURCE_CONSTRAINT)) .addConstraintViolation(); return false; } if (!canManipulateMedia()) { context.buildConstraintViolationWithTemplate("Media operations are not allowed in the current call status.") .addNode(ExceptionMapper.toString(StanzaError.Condition.RESOURCE_CONSTRAINT)) .addConstraintViolation(); return false; } return true; } // Commands // ================================================================================ public void stop(boolean hangup) { if(hangup) { complete(new AskCompleteEvent(model, Reason.NOMATCH)); } else { if (prompt != null) { prompt.getOutput().stop(); prompt.getInput().stop(); } } } // Moho Events // ================================================================================ @State public void onAskComplete(InputCompleteEvent<Participant> event) { if (!event.getMediaOperation().equals(prompt.getInput())) { logger.debug("Ignoring complete event as it is targeted to a different media operation"); return; } AskCompleteEvent completeEvent = null; switch (event.getCause()) { case MATCH: completeEvent = new AskCompleteEvent(model, Reason.SUCCESS); completeEvent.setConcept(event.getConcept()); completeEvent.setInterpretation(event.getInterpretation()); completeEvent.setConfidence(event.getConfidence()); completeEvent.setUtterance(event.getUtterance()); completeEvent.setNlsml(event.getNlsml()); completeEvent.setTag(event.getTag()); completeEvent.setMode(getInputMode(event.getInputMode())); break; case INI_TIMEOUT: completeEvent = new AskCompleteEvent(model, Reason.NOINPUT); break; case IS_TIMEOUT: case MAX_TIMEOUT: completeEvent = new AskCompleteEvent(model, Reason.TIMEOUT); break; case NO_MATCH: completeEvent = new AskCompleteEvent(model, Reason.NOMATCH); break; case CANCEL: completeEvent = new AskCompleteEvent(model, VerbCompleteEvent.Reason.STOP); break; case DISCONNECT: completeEvent = new AskCompleteEvent(model, VerbCompleteEvent.Reason.HANGUP); break; case ERROR: case UNKNOWN: default: complete(new AskCompleteEvent(model, VerbCompleteEvent.Reason.ERROR, findErrorCause(event))); } complete(completeEvent); } private String findErrorCause(com.voxeo.moho.event.InputCompleteEvent<Participant> event) { try { if (isGrxml(model)) { ssmlValidator.validateSsml(model.getPrompt().getText()); } } catch (ValidationException ve) { return ve.getMessage(); } return event.getErrorText() == null ? "Internal Server Error" : event.getErrorText(); } private boolean isGrxml(Ask model) { for (Choices choices: model.getChoices()) { if (choices.getContentType().equalsIgnoreCase(Choices.GRXML_GRAMMAR)) { return true; } } return false; } public void setSsmlValidator(SsmlValidator ssmlValidator) { this.ssmlValidator = ssmlValidator; } }