*Liquidե졼Ȥäץꥱκ
ǤLiquidե졼Ȥäץ륢ץꥱκޤ~
ΤAjax+CometȤäꥢ륿åȥӥǤ

**Action饹ƥץ졼Ȥκ
ޤ˥åȥڡɽ뤿Action饹ƥץ졼Ȥޤ~
***Action饹
LiquidǤAction饹POJOǺ뤿ᡢñActionǤΥ饹ηѾ󥿡եμɬפȤޤ~

 package chat.action;
 
 public class ChatAction
 {
    public String index()
    {
       return "index.ftl";
    }
 }

᥽åɤ1ĺƤޤˤĤƤϸҤޤAction饹ȥ᥽åɤδط򤷤ޤ礦~
LiquidǥեȤWebƥʤǤURLβ褬Τ褦˹Ԥޤ~
 http://xxx.xxx/(ץ饰Х̾)/(Action饹̾)/(᥽å̾)
Τ褦˥줿URLΥѥץ饰Х̾(plugin.xmlιޤ)Action饹̾᥽å̾ФŪAction饹ƤӽФȤߤˤʤäƤޤ~
ǤΤǺChatAction饹Ǥ/ChatAction/indexȤѥǥˤꡢChatAction饹index()ƤӽФޤ~
Action饹ˤϼͳ᥽åɤꤢޤ󤬡URLˤꥢ᥽åɤͤ˥ƥץ졼̾ꤹɬפޤ~
ǻꤵ줿ƥץ졼Ȥ᥽åɤθƤӽФɽΤǡϤΥƥץ졼index.ftlޤ礦~
***ƥץ졼
 <html>
 <body>
 <p>Liquid</p>
 </body>
 </html>

LiquidǤϥǥեȤ[[FreeMarker:http://freemarker.sourceforge.net/]]ƥץ졼ȥ󥸥ͭˤʤäƤޤΤǡFreeMarkerεˡѤǽǤ~
Ȥꤢξ֤ɽ뤫LiquidưƳǧޤ礦ǤLiquidεưˡޤ~

**Liquidεưɬפʤ

Liquidưˤϡץ饰⥸塼module.xmlȥץ饰Τplugin.xmlɬפǤ~
***module.xmlκ
ޤmodule.xmlޤ礦~

 <?xml version="1.0" encoding="euc-jp"?>
 <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
 <beans>
 
     <bean id="moduleManager" class="jp.maru.liquid.kernel.ModuleManager">
         <property name="modules" >
             <list>
                 <bean id="httpTemplateServerModule"
                 class="jp.maru.liquid.kernel.modules.HttpServerModule">
                     <property name="strategy">
                         <bean class="jp.maru.liquid.kernel.modules.strategy.HttpTemplateStrategy" />
                     </property>
                 </bean>
 
                 <bean id="asyncHttpTemplateServerModule"
                 class="jp.maru.liquid.kernel.modules.AsyncHttpServerModule">
                     <property name="strategy">
                         <bean class="jp.maru.liquid.kernel.modules.strategy.HttpBasicStrategy" />
                     </property>
                 </bean>
             </list>
         </property>
     </bean>
 
 </beans>

ChatץꥱǤϥåȥڡɽƱȯ/ɽȯΤǡ줾HttpServerModuleAsyncHttpServerModuleɤޤåȥڡǤϥƥץ졼ȽȯΤǥȥƥȤHttpTemplateStrategyƱǤϥƥץ졼ȽɬפʤΤHttpBasicStrategy򤷤Ƥޤ~
***plugin.xmlκ
plugin.xmlޤ

 <?xml version="1.0" encoding="euc-jp"?>
 <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
 <beans>
 
     <bean id="pluginManager" class="jp.maru.liquid.kernel.PluginManager">
         <property name="plugins">
             <list>
                 <ref local="chatActionPlugin" />
             </list>
         </property>
     </bean>
 
     <bean id="chatActionPlugin"
      class="jp.maru.liquid.core.plugins.HttpActionPlugin">
         <property name="bindURI" value="/chat/*" />
         <property name="encoding" value="utf-8" />
         <property name="templatePath" value="/chat/www/" />
         <property name="actionClass" value="chat.action.*Action" />
     </bean>
 
 </beans>

ȼΥץ饰ȤLiquidȤ߹ޤƤHttpActionPluginȤAction饹ȥƥץ졼ȤΤߤWebץꥱǽǤ~
HttpActionPlugin˰ʲΥץѥƥꤷޤ~
-bindURI - URL˥Хɤ̾ҤΥץ饰Х̾Action¹Ԥˤϡ/xxx/*פȺǸ磻ɥɤˤɬפޤ
-encoding - HTTPإåcharsetѥ᡼Υ󥳡ɤ˻Ѥʸɡ
-templatePath - ƥץ졼Ȥ֤Ƥ١Υǥ쥯ȥѥ
-actionClass - URLؤΥ˸ƤӽФAction饹̾磻ɥɤˤǽ

***ե
ߤޤǤ˺ե֤ޤ/chatȤǥ쥯ȥȤޤ~
ޤɬפȤʤ륵֥ǥ쥯ȥʲΤ褦˺ޤ礦~
 /chat
   /lib
   /src  
   /www 
   /classes
LiquidΥ֤ŸƤjarե/chat/lib졢run.sh/chatذưޤ~
ۤɺChatAction.java/chat/srcˡindex.ftl/chat/wwwˡmodule.xmlplugin.xml/chat֤ޤ~

***ѥ
֤νäChatAction.java򥳥ѥ뤷classե/chat/classesذưޤ~
Action饹Ǥϰ¸ѥå̵ᡢä˥饹ѥλ̵ǥѥ뤬ԤޤLiquid¾Υѥå򻲾ȤŬ饹ѥꤷƥѥ뤷ޤ礦~

***ư
Liquidεưrun.shȤޤñrun.sh¹ԤǵưϤǤ~
ưǧ褿http://xxx.xxx/chat/Chat/index˥ƤߤƲȥڡɽޤ

**ץ饰κ
åȥڡκǤLiquidȹߤΥץ饰ȤäΤǡ˥ץ饰ɬפ̵äǤƱ˥åȥåɤ߹ˤϤѤνɬפˤʤΤǥץ饰ޤ~
CometǤϥΥ֥å̿Ԥɬפ뤿ᡢץ饰ǤϥΥ֥å̿б⥸塼AsyncHttpServerModuleѤޤAsyncHttpServerModuleȤˤAsyncHttpServerPlugin󥿡եɬפޤ~
ޤΥץ饰Ǥϥƥץ졼ȤϻѤʤΤǥȥƥHttpBasicStrategyȤޤHttpBasicStrategyǥץ饰ˤHttpBasicPlugin󥿡եޤ~

 package chat.plugin;
 
 import java.util.List;
 import java.util.ArrayList;
 import java.io.IOException;
 
 import jp.maru.liquid.plugin.http.HttpRequest;
 import jp.maru.liquid.plugin.http.HttpResponse;
 import jp.maru.liquid.plugin.http.AsyncHttpEvent;
 import jp.maru.liquid.plugin.http.AsyncTrigger;
 import jp.maru.liquid.plugin.AsyncHttpServerPlugin;
 import jp.maru.liquid.plugin.HttpBasicPlugin;
 
 public class ChatPlugin implements AsyncHttpServerPlugin,HttpBasicPlugin
 {
     private List<AsyncTrigger> _triggerList=new ArrayList<AsyncTrigger>();
     private String _lastMessage;
     private String _bindURI;
 
     @Override
     public void init()
     {
     }
 
     @Override
     public void execute(HttpRequest request,HttpResponse response)
     throws IOException
     {
         response.setContentType("text/html; charset=UTF-8");
         response.getWriter().println(_lastMessage != null? _lastMessage: "");
     }
 
     @Override
     public void httpConnected(AsyncHttpEvent event,AsyncTrigger trigger)
     {
 
         _triggerList.add(trigger);
     }
 
     @Override
     public void httpDisconnected(AsyncHttpEvent event)
     {
     }
 
     public synchronized void message(String handle,String message)
     {
         try
         {
             _lastMessage=handle+": "+message;
 
             for(AsyncTrigger trigger : _triggerList)
                 trigger.resume();
             _triggerList.clear();
             _lastMessage=null;
         }
         catch(IOException ioe)
         {
             ioe.printStackTrace();
         }
     }
 
     @Override
     public String getBindURI()
     {
         return _bindURI;
     }
 
     public void setBindURI(String uri)
     {
         _bindURI=uri;
     }
 }

󥿡եAsyncHttpServerPluginˤ³˥뤵᥽åhttpConnected()ǻ˥뤵᥽åhttpDisconnected()Ƥ뤿ᡢ줾Ԥޤ~
httpConnected()Ǥ³ԤäƤ饤ȤΥ֥AsyncTriggerץ饰ChatPluginΥ󥹥ѿȤѰդListɲäƤԤäƤޤhttpDisconnected()ǤϽԤޤ~
󥿡եHttpBasicPluginˤϥ᥽åexecute()ƤΤǤޤΥ᥽åɤǤϥץ饰Ϥ줿åȥå򥯥饤ȤԤޤ~
᥽åmessage()ǤϸҤAction饹θƤӽФơ饤ȤƤåץ饰Υ󥹥ѿ¸ListϿƤ륯饤ȤФƤԤäƤޤ~
Υ饹AsyncTriggerΥ᥽åresume()ˤꡢߤƤ饤ȤΥꥯȤƳ饤˥᥽åexecute()ƤӽФޤ~
ץ饰ϤǴǤ˥饤ȤΥåAction饹ɲäޤ礦

**Action饹ν
饤ȤAjaxˤȯ˥ϥɥ롢åͤˤ뤿ᡢơΥѥ᡼Ǥ褦ѹޤLiquidWebƥʤǤϥѥ᡼setȤ᥽åɤˤΤǡsetHandle()setMsg()Ȥ᥽åɤޤ~
äȯμƱѰդChatPluginΥ᥽åmessage()ФȯƤݥȤ褦ˤ⤷ޤ礦~

 package chat.action;
 
 import jp.maru.liquid.plugin.Plugin;
 import jp.maru.liquid.core.plugins.http.annotation.Intercept;
 import jp.maru.liquid.core.plugins.http.annotation.InjectPlugin;
 import jp.maru.liquid.core.plugins.http.interceptor.PluginInterceptor;
 import jp.maru.liquid.core.plugins.http.interceptor.PluginAware;
 import chat.plugin.ChatPlugin;
 
 @Intercept(PluginInterceptor.class)
 @InjectPlugin(ChatPlugin.class)
 public class ChatAction implements PluginAware
 {
     private ChatPlugin _chatPlugin;
     private String _handle,_msg;
 
     public String index()
     {
         return "index.ftl";
     }
 
     public String jquery()
     {
         return "jquery.min.js";
     }
 
     public String msg()
     {
         _chatPlugin.message(_handle,_msg);
 
         return "dummy.ftl";
     }
 
 
     public void setHandle(String handle)
     {
         _handle=handle;
     }
 
     public void setMsg(String msg)
     {
         _msg=msg;
     }
 
     @Override
     public void setPlugin(Plugin[] plugins)
     {
         _chatPlugin=(ChatPlugin)plugins[0];
     }
 }
 
饹ФƥΥơ@Intercept@InjectPluginꤷƤޤ~
Υơ@InterceptϤAction˥ꥯȤ夹˽륤󥿡ץꤷޤϥץ饰򥤥󥸥ȤΤǡPluginInterceptorꤷƤޤ~
Υơ@InjectPluginϥ󥸥Ȥץ饰̾ꤷޤ~
ΥΥơˤꥤ󥿡ץActionsetPlugin̤ŪΥץ饰򥤥󥸥ȤActionľܥץ饰إǽˤʤޤ~
ActionνϤǴλǤϥƥץ졼Ȥޤ礦~

**ƥץ졼Ȥν
ƥץ졼ȤǤϥåȤȯȯΥɤФΤǡͳ˺äƤäƹޤ~
jQueryȤAjax̿ʬƤޤjQueryΥ饤֥jquery.min.js/chat/www֤ޤ礦~

 <html>
 <head>
 <style type="text/css">
 <!--
 body > * {
     font-size:0.8em;
 }
 #chat {
     width:420px;
     height:250px;
     border:2px solid #FA5;
     overflow:auto;
     margin-top:10px;
     padding:3px;
 }
 
 #handle,#msg {
     border:2px solid #F75;
 }
 -->
 </style>
 </head>
 <body>
 <p>Liquid Sample - Comet Chat</p>
 
 <input type="text" id="handle" size="15"><input type="text" id="msg" size="40">
 <br>
 
 <div id="chat"></div>
 
 <script type="text/javascript" src="/chat/Chat/jquery"></script>
 <script type="text/javascript">
 <!--
 $(document).ready(function()
 {
     $("#msg").keypress(checkReturn);
     waitResponse();
 });
 
 function sendMsg()
 {
     $.get("/chat/Chat/msg",{handle:$("#handle").val(),msg:$("#msg").val()});
     $("#msg").val("");
 }
 
 function waitResponse()
 {
     $.get("/chatComet/",function(response){
         if(response.length > 0)
             $("#chat").html(response+"<br>"+$("#chat").html());
         waitResponse();
     });
 }
 
 function checkReturn(event)
 {
     var keyCode = event.keyCode ? event.keyCode : event.which ? event.which : event.charCode;
     if(keyCode==13)
         sendMsg();
 }
 
 //-->
 </script>
 </body>
 </html>

ǥץ饰ϤȤꤢλǤǸplugin.xmlν򤷤ޤ礦

**plugin.xmlν
ۤɺäChatPluginplugin.xmlϿޤ~
ʲƤ˽񤭴Ʋ~

 <?xml version="1.0" encoding="euc-jp"?>
 <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
 <beans>
 
     <bean id="pluginManager" class="jp.maru.liquid.kernel.PluginManager">
         <property name="plugins" >
             <list>
                 <ref local="chatPlugin" />
                 <ref local="chatActionPlugin" />
             </list>
         </property>
     </bean>
 
     <bean id="chatPlugin"
      class="chat.plugin.ChatPlugin">
         <property name="bindURI" value="/chatComet/" />
     </bean>
 
     <bean id="chatActionPlugin"
      class="jp.maru.liquid.core.plugins.HttpActionPlugin">
         <property name="bindURI" value="/chat/*" />
         <property name="encoding" value="utf-8" />
         <property name="templatePath" value="/chat/www/" />
         <property name="actionClass" value="chat.action.*Action" />
     </bean>
 
 </beans>

**ѥ롢¹
˥饹äΤǥѥԤޤ/chat/libȤ򥯥饹ѥ˲äƥѥ뤷ޤ礦~
ʤѥ뤬λ顢run.shˤäLiquidưޤ~
http://xxx.xxx/chat/Chat/index˥ƥåȤǤ~

**ޤȤ
LiquidϷ̤ʥե졼Ǥ⤤ĥäƤޤ~
ǽץ饰Ȥ󶡤ˤꥪ֥ȴ֤ΰ¸㤯ƥʥ⤯ѲǽʥƥιۤŪȤƺޤ~
ϿޤǤ¾ñμ¹ԲǽPlugin򥵥ݡȤExecuteModule³ؤHibernateΥݡȡΥơˤХǡʤɤεǽܤƤޤ~
WebץꥱΤߤʤ餺ХɥץꥱۤΤˤŬե졼ʤΤǳѤƤ館ФȻפޤ~
ǤϤ褤Liquid饤դ
