View Javadoc
1   /*
2    * Copyright (c) 2002-2017, Mairie de Paris
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    *
9    *  1. Redistributions of source code must retain the above copyright notice
10   *     and the following disclaimer.
11   *
12   *  2. Redistributions in binary form must reproduce the above copyright notice
13   *     and the following disclaimer in the documentation and/or other materials
14   *     provided with the distribution.
15   *
16   *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
17   *     contributors may be used to endorse or promote products derived from
18   *     this software without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   * POSSIBILITY OF SUCH DAMAGE.
31   *
32   * License 1.0
33   */
34  package fr.paris.lutece.plugins.chatbot.web;
35  
36  import fr.paris.lutece.plugins.chatbot.business.BotDescription;
37  import fr.paris.lutece.plugins.chatbot.service.bot.ChatBot;
38  import fr.paris.lutece.plugins.chatbot.business.Post;
39  import fr.paris.lutece.plugins.chatbot.service.BotService;
40  import static fr.paris.lutece.plugins.chatbot.service.BotService.getBots;
41  import fr.paris.lutece.plugins.chatbot.service.ChatService;
42  import fr.paris.lutece.portal.service.util.AppPathService;
43  import fr.paris.lutece.portal.service.util.AppPropertiesService;
44  import fr.paris.lutece.portal.util.mvc.commons.annotations.Action;
45  import fr.paris.lutece.portal.util.mvc.commons.annotations.View;
46  import fr.paris.lutece.portal.util.mvc.xpage.MVCApplication;
47  import fr.paris.lutece.portal.util.mvc.xpage.annotations.Controller;
48  import fr.paris.lutece.portal.web.l10n.LocaleService;
49  import fr.paris.lutece.portal.web.xpages.XPage;
50  import fr.paris.lutece.util.url.UrlItem;
51  
52  import java.util.ArrayList;
53  import java.util.HashMap;
54  import java.util.List;
55  import java.util.Locale;
56  import java.util.Map;
57  import java.util.UUID;
58  
59  import javax.servlet.http.HttpServletRequest;
60  
61  /**
62   * This class provides a simple implementation of an XPage
63   */
64  @Controller( xpageName = "chatbot", pageTitleI18nKey = "chatbot.xpage.bot.pageTitle", pagePathI18nKey = "chatbot.xpage.bot.pagePathLabel" )
65  public class ChatBotApp extends MVCApplication
66  {
67      private static final String TEMPLATE_BOT = "/skin/plugins/chatbot/bot.html";
68      private static final String TEMPLATE_BOT_STANDALONE = "/skin/plugins/chatbot/bot_standalone.html";
69      private static final String TEMPLATE_BOTS_LIST = "/skin/plugins/chatbot/bots_list.html";
70      private static final String MARK_BOTS_LIST = "bots_list";
71      private static final String MARK_POSTS_LIST = "posts_list";
72      private static final String MARK_BOT_AVATAR = "bot_avatar";
73      private static final String MARK_BASE_URL = "base_url";
74      private static final String MARK_BOT = "bot";
75      private static final String MARK_LANGUAGE = "language";
76      private static final String MARK_STANDALONE = "standalone";
77      private static final String MARK_TYPED_SCRIPT = "typed_script";
78      private static final String PARAMETER_BOT = "bot";
79      private static final String PARAMETER_RESPONSE = "response";
80      private static final String PARAMETER_LANGUAGE = "lang";
81      private static final String PARAMETER_STANDALONE = "standalone";
82      private static final String PARAMETER_BUTTON_VALUE = "button_value";
83      private static final String VIEW_LIST = "list";
84      private static final String VIEW_BOT = "bot";
85      private static final String ACTION_RESPONSE = "response";
86      private static final String ACTION_BUTTON_RESPONSE = "button_click";
87      private static final String URL_BOT = "jsp/site/Portal.jsp?page=chatbot&view=bot";
88      private static final String PROPERTY_STANDALONE = "chatbot.standalone";
89      private static final String PROPERTY_TYPED_SCRIPT = "chatbot.typed_script.enabled";
90      
91      private static final boolean DEFAULT_TYPED_SCRIPT = true;
92  
93      private static final long serialVersionUID = 1L;
94  
95      private String _strBotKey;
96      private Locale _locale;
97      private String _strConversationId;
98      private ChatBot _bot;
99      private boolean _bStandalone;
100 
101     /**
102      * Returns the content of the list of bots page
103      * 
104      * @param request
105      *            The HTTP request
106      * @return The page
107      */
108     @View( value = VIEW_LIST, defaultView = true )
109     public XPage viewList( HttpServletRequest request )
110     {
111         List<BotDescription> listBots = getBotsDescription( );
112 
113         Map<String, Object> model = getModel( );
114         model.put( MARK_BOTS_LIST, listBots );
115 
116         return getXPage( TEMPLATE_BOTS_LIST, request.getLocale( ), model );
117     }
118 
119     /**
120      * Returns the content of the bot page.
121      * 
122      * @param request
123      *            The HTTP request
124      * @return The page
125      */
126     @View( VIEW_BOT )
127     public XPage viewBot( HttpServletRequest request )
128     {
129         String strBotKey = request.getParameter( PARAMETER_BOT );
130         if ( strBotKey == null )
131         {
132             // assuming the bot is the current session bot
133             if ( _strBotKey == null )
134             {
135                 // session is closed
136                 return redirectView( request, VIEW_LIST );
137             }
138         }
139         else
140         {
141             if ( !strBotKey.equals( _strBotKey ) )
142             {
143                 // new bot or bot has changed
144                 initSessionParameters( request, strBotKey );
145             }
146         }
147         boolean bTypedScript = AppPropertiesService.getPropertyBoolean( PROPERTY_TYPED_SCRIPT , DEFAULT_TYPED_SCRIPT );
148         List<Post> listPosts = ChatService.getConversation( _strConversationId, _bot, _locale );
149         Map<String, Object> model = getModel( );
150         model.put( MARK_POSTS_LIST, listPosts );
151         model.put( MARK_BOT_AVATAR, _bot.getAvatarUrl( ) );
152         model.put( MARK_BASE_URL, AppPathService.getBaseUrl( request ) );
153         model.put( MARK_BOT, _strBotKey );
154         model.put( MARK_LANGUAGE, _locale.getLanguage( ) );
155         model.put( MARK_STANDALONE, ( _bStandalone ) ? "true" : "false" );
156         model.put(  MARK_TYPED_SCRIPT , bTypedScript );
157 
158         String strTemplate = ( _bStandalone ) ? TEMPLATE_BOT_STANDALONE : TEMPLATE_BOT;
159         XPage xpage = getXPage( strTemplate, request.getLocale( ), model );
160         xpage.setTitle( _bot.getName( _locale ) );
161         xpage.setPathLabel( _bot.getName( _locale ) );
162         xpage.setStandalone( _bStandalone );
163 
164         return xpage;
165     }
166 
167     /**
168      * Process the response
169      * 
170      * @param request
171      *            The HTTP request
172      * @return The redirected page
173      */
174     @Action( ACTION_RESPONSE )
175     public XPage doProcessMessage( HttpServletRequest request )
176     {
177         if ( !checkSession( request ) )
178         {
179             return redirectView( request, VIEW_LIST );
180         }
181 
182         String strMessage = request.getParameter( PARAMETER_RESPONSE );
183 
184         ChatService.processMessage( request, _strConversationId, strMessage, _strBotKey, _locale );
185         Map<String, String> mapParameters = new HashMap<>( );
186         mapParameters.put( PARAMETER_BOT, _strBotKey );
187         mapParameters.put( PARAMETER_LANGUAGE, _locale.getLanguage( ) );
188         mapParameters.put( PARAMETER_STANDALONE, _bStandalone ? "true" : "false" );
189 
190         return redirect( request, VIEW_BOT, mapParameters );
191     }
192 
193     /**
194      * Process Button click
195      * 
196      * @param request
197      *            The HTTP request
198      * @return The redirected page
199      */
200     @Action( ACTION_BUTTON_RESPONSE )
201     public XPage doProcessButtonMessage( HttpServletRequest request )
202     {
203         if ( !checkSession( request ) )
204         {
205             return redirectView( request, VIEW_LIST );
206         }
207 
208         String strMessage = request.getParameter( PARAMETER_BUTTON_VALUE );
209 
210         ChatService.processMessage( request, _strConversationId, strMessage, _strBotKey, _locale );
211         Map<String, String> mapParameters = new HashMap<>( );
212         mapParameters.put( PARAMETER_BOT, _strBotKey );
213         mapParameters.put( PARAMETER_LANGUAGE, _locale.getLanguage( ) );
214         mapParameters.put( PARAMETER_STANDALONE, _bStandalone ? "true" : "false" );
215 
216         return redirect( request, VIEW_BOT, mapParameters );
217     }
218 
219     /**
220      * Get request information for the bot language
221      * 
222      * @param request
223      *            The request
224      * @return The locale
225      */
226     private Locale getBotLocale( HttpServletRequest request )
227     {
228         String strLanguage = request.getParameter( PARAMETER_LANGUAGE );
229 
230         if ( strLanguage != null )
231         {
232             return new Locale( strLanguage );
233         }
234 
235         return LocaleService.getDefault( );
236     }
237 
238     /**
239      * Gets the list of bots
240      * 
241      * @return The list of bots
242      */
243     private List<BotDescription> getBotsDescription( )
244     {
245         List<BotDescription> list = new ArrayList<BotDescription>( );
246 
247         for ( ChatBot bot : getBots( ) )
248         {
249             List<String> listLanguages = bot.getAvailableLanguages( );
250 
251             if ( listLanguages != null )
252             {
253                 for ( String strLanguage : listLanguages )
254                 {
255                     BotDescription botDescription = new BotDescription( );
256                     Locale locale = new Locale( strLanguage );
257                     botDescription.setName( bot.getName( locale ) );
258                     botDescription.setDescription( bot.getDescription( locale ) );
259                     botDescription.setLanguage( locale.getDisplayLanguage( ) );
260                     botDescription.setAvatarUrl( bot.getAvatarUrl( ) );
261 
262                     UrlItem url = new UrlItem( URL_BOT );
263                     url.addParameter( PARAMETER_BOT, bot.getKey( ) );
264                     url.addParameter( PARAMETER_LANGUAGE, strLanguage );
265                     botDescription.setUrl( url.getUrl( ) );
266                     list.add( botDescription );
267                 }
268             }
269             else
270             {
271                 BotDescription botDescription = new BotDescription( );
272                 Locale locale = LocaleService.getDefault( );
273                 botDescription.setName( bot.getName( locale ) );
274                 botDescription.setDescription( bot.getDescription( locale ) );
275                 botDescription.setLanguage( locale.getDisplayLanguage( ) );
276                 UrlItem url = new UrlItem( URL_BOT );
277                 url.addParameter( PARAMETER_BOT, bot.getKey( ) );
278                 url.addParameter( PARAMETER_LANGUAGE, locale.getLanguage() );
279                 botDescription.setUrl( url.getUrl( ) );
280                 list.add( botDescription );
281             }
282         }
283 
284         return list;
285     }
286 
287     /**
288      * Generate a Conversation ID
289      * 
290      * @return The ID
291      */
292     private String getNewConversationId( )
293     {
294         return UUID.randomUUID( ).toString( );
295     }
296 
297     /**
298      * Gets the running mode according configuration and runtime parameters
299      * 
300      * @param request
301      *            The HTTP request
302      * @return true if the current bit should be run in standalone mode
303      */
304     private boolean getStandalone( HttpServletRequest request )
305     {
306         String strStandalone = request.getParameter( PARAMETER_STANDALONE );
307         if ( strStandalone != null && ( strStandalone.equalsIgnoreCase( "true" ) || strStandalone.equalsIgnoreCase( "on" ) ) )
308         {
309             return true;
310         }
311         strStandalone = AppPropertiesService.getProperty( PROPERTY_STANDALONE );
312         if ( strStandalone != null && ( strStandalone.equalsIgnoreCase( "true" ) || strStandalone.equalsIgnoreCase( "on" ) ) )
313         {
314             return true;
315         }
316         return false;
317     }
318 
319     /**
320      * Check the session
321      * 
322      * @param request
323      *            The HTTP request
324      * @return true if the bot session is active or can be restarted otherwise false
325      */
326     private boolean checkSession( HttpServletRequest request )
327     {
328         if ( _strBotKey == null )
329         {
330             String strBotKey = request.getParameter( PARAMETER_BOT );
331             if ( strBotKey != null )
332             {
333                 initSessionParameters( request, strBotKey );
334             }
335             else
336             {
337                 return false;
338             }
339         }
340         return true;
341     }
342 
343     /**
344      * Initialize session datas
345      * 
346      * @param request
347      *            The request
348      * @param strBotKey
349      *            The bot key
350      */
351     private void initSessionParameters( HttpServletRequest request, String strBotKey )
352     {
353         _strBotKey = strBotKey;
354         _bot = BotService.getBot( _strBotKey );
355         _locale = getBotLocale( request );
356         _strConversationId = getNewConversationId( );
357         _bStandalone = ( _bot.isStandalone( ) ) ? true : getStandalone( request );
358     }
359 }