1   package org.daisy.pipeline.tts.impl;
2   
3   import java.io.IOException;
4   import java.util.Collections;
5   import java.util.IllformedLocaleException;
6   import java.util.Locale;
7   
8   import net.sf.saxon.s9api.SaxonApiException;
9   import net.sf.saxon.s9api.XdmNode;
10  
11  import org.daisy.common.properties.Properties;
12  import org.daisy.pipeline.tts.Voice;
13  import org.daisy.pipeline.tts.VoiceInfo.Gender;
14  import org.daisy.pipeline.tts.VoiceManager;
15  import org.daisy.pipeline.webservice.restlet.AuthenticatedResource;
16  import org.daisy.pipeline.webservice.xml.XmlUtils;
17  
18  import org.restlet.data.MediaType;
19  import org.restlet.data.Status;
20  import org.restlet.ext.xml.DomRepresentation;
21  import org.restlet.representation.Representation;
22  import org.restlet.resource.Get;
23  import org.restlet.resource.Post;
24  
25  import org.slf4j.Logger;
26  import org.slf4j.LoggerFactory;
27  
28  import org.w3c.dom.Document;
29  import org.w3c.dom.Element;
30  
31  public class VoicesResource extends AuthenticatedResource {
32  
33  	private static final Logger logger = LoggerFactory.getLogger(VoicesResource.class.getName());
34  
35  	private VoicesWebServiceExtension provider;
36  	private String engineAttr;
37  	private String nameAttr;
38  	private String langAttr;
39  	private String genderAttr;
40  
41  	@SuppressWarnings("unchecked")
42  	@Override
43  	public void doInit() {
44  		super.doInit();
45  		if (!isAuthenticated()) {
46  			return;
47  		}
48  		provider = (VoicesWebServiceExtension)getContext().getAttributes().get(VoicesWebServiceExtension.CONTEXT_ATTRIBUTE_KEY);
49  		engineAttr = getQuery().getFirstValue("engine");
50  		nameAttr = getQuery().getFirstValue("name");
51  		langAttr = getQuery().getFirstValue("lang");
52  		genderAttr = getQuery().getFirstValue("gender");
53  	}
54  
55  	/**
56  	 * Gets the resource.
57  	 *
58  	 * @return the resource
59  	 */
60  	@Get("xml")
61  	public Representation getResource() {
62  		return getResource(null);
63  	}
64  
65  	/**
66  	 * @param ttsConfig
67  	 */
68  	@Post("xml")
69  	public Representation getResource(Representation ttsConfig) {
70  		logRequest();
71  		maybeEnableCORS();
72  		if (!isAuthenticated()) {
73  			setStatus(Status.CLIENT_ERROR_UNAUTHORIZED);
74  			return null;
75  		}
76  		XdmNode configXML = null; {
77  			if (ttsConfig != null)
78  				try {
79  					configXML = provider.getConfigXML(ttsConfig.getText());
80  				} catch (IOException|SaxonApiException e) {
81  					logger.error("bad request:", e);
82  					setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
83  					return getErrorRepresentation(e.getMessage());
84  				}
85  		}
86  		VoiceManager voiceManager = null;
87  		boolean omitRefs = false; {
88  			synchronized (provider) {
89  				voiceManager = provider.getVoiceManager(Properties.getSnapshot(), configXML, logger);
90  				omitRefs = !provider.hasRememberedVoiceManager();
91  			}
92  		}
93  		Iterable<Voice> availableVoices; {
94  			Locale lang; {
95  				try {
96  					lang = langAttr == null ? null : (new Locale.Builder()).setLanguageTag(langAttr).build();
97  					Gender gender = Gender.of(genderAttr);
98  					if (gender != null || genderAttr == null) {
99  						String voiceEngine = engineAttr;
100 						String voiceName = nameAttr;
101 						logger.debug("Getting voices for query " + getQuery());
102 						availableVoices = voiceManager.findAvailableVoices(voiceEngine, voiceName, lang, gender);
103 					} else {
104 						logger.error("Could not parse gender '" + genderAttr + "'");
105 						availableVoices = Collections.EMPTY_LIST;
106 					}
107 				} catch (IllformedLocaleException e) {
108 					logger.error(e.getMessage());
109 					availableVoices = Collections.EMPTY_LIST;
110 				}
111 			}
112 		}
113 		Document voicesDoc; {
114 			voicesDoc = XmlUtils.createDom("voices");
115 			Element voicesElem = voicesDoc.getDocumentElement();
116 			String baseURL = getRequest().getRootRef().toString();
117 			voicesElem.setAttribute("href", baseURL + VoicesWebServiceExtension.VOICES_ROUTE);
118 			for (Voice v : availableVoices) {
119 				Element voiceElem = voicesDoc.createElementNS(XmlUtils.NS_PIPELINE_DATA, "voice");
120 				VoiceResource.addElementData(voiceElem, baseURL, v, omitRefs);
121 				voicesElem.appendChild(voiceElem);
122 			}
123 		}
124 		DomRepresentation dom; {
125 			try {
126 				dom = new DomRepresentation(MediaType.APPLICATION_XML, voicesDoc);
127 				setStatus(Status.SUCCESS_OK);
128 			} catch (Exception e) {
129 				setStatus(Status.SERVER_ERROR_INTERNAL);
130 				return getErrorRepresentation(e.getMessage());
131 			}
132 		}
133 		logResponse(dom);
134 		return dom;
135 	}
136 }