<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆 - 19, 文章 - 1, 評論 - 21, 引用 - 0
    數據加載中……

    打造一個基于OSGi的Web Application——使用Tomcat原生API動態管理Listener

    本文介紹在Tomcat中,如何通過Tomcat原生API實現OSGi容器中動態管理Listener。

    首先建個接口類,用于描述注冊Listener所使用的Service:
     1 package org.dbstar.osgi.web.register;
     2 
     3 import java.util.EventListener;
     4 
     5 import org.osgi.framework.Bundle;
     6 
     7 public interface ListenerService {
     8     /**
     9      * 判斷當前ListenerService實現是否支持使用Listener實例。Service的使用者可以根據此參數來選擇適合的調用方式。
    10      * 
    11      * <pre>
    12      * 1.如果支持使用Listener實例,那么在addApplicationListener(Bundle, ListenerRegistration, EventListener)方法中的
    13      * EventListener實例將被直接注冊到Web Context中去,從而使得Listener實例中的預設環境得以保留。
    14      * 2.如果不支持使用Listener實例,那么不管調用哪個addApplicationListener方法,新的實例總是會根據提供的ListenerRegistration
    15      * 創建出來,而方法中的EventListener參數將被忽略。
    16      * </pre>
    17      * 
    18      * @return 當前ListenerService實現是否支持使用Listener實例。
    19      */
    20     public boolean supportsListenerInstance();
    21 
    22     /**
    23      * 根據提供的ListenerRegistration來注冊一個新的Listener到Web Context中。
    24      * 
    25      * @param bundle 注冊listener的bundle
    26      * @param registration Listener注冊信息
    27      * @return 新增加的Listener的系統名稱,這個名稱用于調用removeApplicationListener方法
    28      * @exception IllegalArgumentException 如果根據提供的ListenerRegistration不能創建Listener實例
    29      * @exception IllegalArgumentException 如果待增加的Listener在Web Context中不唯一
    30      */
    31     public String addApplicationListener(Bundle bundle, ListenerRegistration registration);
    32 
    33     /**
    34      * 根據提供的ListenerRegistration和Listener實例來注冊一個新的Listener到Web Context中。
    35      * 
    36      * <pre>
    37      * 根據supportsListenerInstance返回的結果不同,此方法有不同的處理方式:
    38      * 1.如果supportsListenerInstance返回true,那么方法中的Listener實例參數將被直接注冊到Web Context中去。
    39      * 2.如果supportsListenerInstance返回false,那么方法中的Listener實例參數將被忽略,Listener實例將根據ListenerRegistration來創建。
    40      * </pre>
    41      * 
    42      * @param bundle 注冊listener的bundle
    43      * @param registration Listener注冊信息
    44      * @param listener Listener實例
    45      * @return 新增加的Listener的系統名稱,這個名稱用于調用removeApplicationListener方法
    46      * @exception IllegalArgumentException 如果根據提供的ListenerRegistration不能創建Listener實例
    47      * @exception IllegalArgumentException 如果待增加的Listener在Web Context中不唯一
    48      */
    49     public String addApplicationListener(Bundle bundle, ListenerRegistration registration, EventListener listener);
    50 
    51     /**
    52      * 從Web Context中刪除指定的Listener。
    53      * 
    54      * @param listenerName 待刪除Listener對應的系統名稱,這個名稱通過addApplicationListener方法返回值獲得
    55      */
    56     public void removeApplicationListener(String listenerName);
    57 }

    然后是ListenerRegistration,用于記載注冊Listener時所提供的信息:
     1 package org.dbstar.osgi.web.register;
     2 
     3 import java.util.EventListener;
     4 
     5 public final class ListenerRegistration extends GeneralInfo<ListenerRegistration> {
     6     private static final long serialVersionUID = -6201323709943780698L;
     7 
     8     private Class<? extends EventListener> listenerClass;
     9 
    10     public ListenerRegistration(Class<? extends EventListener> listenerClass) {
    11         this.listenerClass = listenerClass;
    12     }
    13 
    14     public Class<? extends EventListener> getListenerClass() {
    15         return listenerClass;
    16     }
    17 }

     1 package org.dbstar.osgi.web.register;
     2 
     3 import java.io.Serializable;
     4 
     5 public abstract class GeneralInfo<T> implements Serializable {
     6     private static final long serialVersionUID = -5739502239414925563L;
     7 
     8     private String description;
     9     private String displayName;
    10     private Icon icon;
    11 
    12     public final String getDescription() {
    13         return description;
    14     }
    15 
    16     @SuppressWarnings("unchecked")
    17     public final T setDescription(String description) {
    18         this.description = description;
    19         return (T) this;
    20     }
    21 
    22     public final String getDisplayName() {
    23         return displayName;
    24     }
    25 
    26     @SuppressWarnings("unchecked")
    27     public final T setDisplayName(String displayName) {
    28         this.displayName = displayName;
    29         return (T) this;
    30     }
    31 
    32     public final Icon getIcon() {
    33         return icon;
    34     }
    35 
    36     @SuppressWarnings("unchecked")
    37     public final T setIcon(Icon icon) {
    38         this.icon = icon;
    39         return (T) this;
    40     }
    41 }

     1 package org.dbstar.osgi.web.register;
     2 
     3 import java.io.Serializable;
     4 
     5 public final class Icon implements Serializable {
     6     private static final long serialVersionUID = 5232737399172945853L;
     7 
     8     private String smallIcon;
     9     private String largeIcon;
    10 
    11     public String getSmallIcon() {
    12         return smallIcon;
    13     }
    14 
    15     public Icon setSmallIcon(String smallIcon) {
    16         this.smallIcon = smallIcon;
    17         return this;
    18     }
    19 
    20     public String getLargeIcon() {
    21         return largeIcon;
    22     }
    23 
    24     public Icon setLargeIcon(String largeIcon) {
    25         this.largeIcon = largeIcon;
    26         return this;
    27     }
    28 }

    細心的同學可能已經發現了,ListenerRegistration類定義的屬性與Servlet 2.4的web.xml中,<listener>標簽的描述是一致的。

    好了,Service接口定義好了,下面我們來寫一個實現類,還是使用DS方式:
    ListenerService.xml:
     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="TomcatListenerService"
     3     xsi:schemaLocation="http://www.osgi.org/xmlns/scr/v1.1.0 http://www.osgi.org/xmlns/scr/v1.1.0/scr.xsd">
     4     <implementation class="org.dbstar.osgi.web.register.tomcat.ListenerServiceImpl" />
     5     <reference cardinality="1..1" interface="org.apache.catalina.Context" name="Context" policy="static" />
     6     <reference bind="bindLog" cardinality="0..1" interface="org.osgi.service.log.LogService" name="LogService"
     7         policy="static" unbind="unbindLog" />
     8     <service>
     9         <provide interface="org.dbstar.osgi.web.register.ListenerService" />
    10     </service>
    11 </scr:component>
    接下來是ListenerServiceImpl,當然了,它必須實現ListenerService接口:
      1 package org.dbstar.osgi.web.register.tomcat;
      2 
      3 import java.util.ArrayList;
      4 import java.util.EventListener;
      5 import java.util.HashMap;
      6 import java.util.List;
      7 import java.util.Map;
      8 import java.util.Set;
      9 
     10 import javax.servlet.ServletContextAttributeListener;
     11 import javax.servlet.ServletContextEvent;
     12 import javax.servlet.ServletContextListener;
     13 import javax.servlet.ServletRequestAttributeListener;
     14 import javax.servlet.ServletRequestListener;
     15 import javax.servlet.http.HttpSessionAttributeListener;
     16 import javax.servlet.http.HttpSessionEvent;
     17 import javax.servlet.http.HttpSessionListener;
     18 
     19 import org.apache.catalina.Context;
     20 import org.apache.catalina.Session;
     21 import org.dbstar.osgi.web.register.ListenerRegistration;
     22 import org.dbstar.osgi.web.register.ListenerService;
     23 import org.osgi.framework.Bundle;
     24 import org.osgi.framework.BundleEvent;
     25 import org.osgi.framework.BundleListener;
     26 import org.osgi.service.component.ComponentContext;
     27 import org.osgi.service.log.LogService;
     28 
     29 public class ListenerServiceImpl implements ListenerService, BundleListener {
     30     private Context context;
     31     private LogService log;
     32 
     33     /**
     34      * Bundle ID和ListenerName數組的映射,通過Bundle ID找到所有此Bundle注冊的Listener的系統名稱
     35      */
     36     private Map<Long, List<String>> bnsMap = new HashMap<Long, List<String>>();
     37 
     38     /**
     39      * ListenerName和Listener實例的映射,通過ListenerName找到對應的Listener實例
     40      */
     41     private Map<String, EventListener> nlMap = new HashMap<String, EventListener>();
     42 
     43     /**
     44      * ListenerName和Bundle ID的映射,通過ListenerName找到對應的注冊此Listener的Bundle的ID
     45      */
     46     private Map<String, Long> nbMap = new HashMap<String, Long>();
     47 
     48     protected void activate(ComponentContext context) {
     49         // 獲取org.apache.catalina.Context
     50         this.context = (Context) context.locateService("Context");
     51         context.getBundleContext().addBundleListener(this);
     52     }
     53 
     54     protected void deactivate(ComponentContext context) {
     55         context.getBundleContext().removeBundleListener(this);
     56         // 在destroy方法中注銷所有注冊的Listener
     57         destroy();
     58         this.context = null;
     59     }
     60 
     61     protected void bindLog(LogService log) {
     62         this.log = log;
     63     }
     64 
     65     protected void unbindLog(LogService log) {
     66         if (this.log == log) this.log = null;
     67     }
     68 
     69     public void bundleChanged(BundleEvent event) {
     70         if (event.getType() == BundleEvent.STOPPED) {
     71             // 在Bundle Stop之后注銷所有此Bundle注冊的Listener
     72             Long bundleId = event.getBundle().getBundleId();
     73             synchronized (this) {
     74                 if (bnsMap.containsKey(bundleId)) {
     75                     List<String> nameList = bnsMap.get(bundleId);
     76                     for (String listenerName : nameList.toArray(new String[nameList.size()])) {
     77                         removeApplicationListener(bundleId, listenerName);
     78                     }
     79                 }
     80             }
     81         }
     82     }
     83 
     84     /*
     85      * (non-Javadoc)
     86      * 
     87      * @see org.dbstar.osgi.web.register.ListenerService#supportsListenerInstance()
     88      */
     89     public boolean supportsListenerInstance() {
     90         return true;
     91     }
     92 
     93     /*
     94      * (non-Javadoc)
     95      * 
     96      * @see org.dbstar.osgi.web.register.ListenerService#addApplicationListener(org.osgi.framework.Bundle,
     97      * org.dbstar.osgi.web.register.ListenerRegistration)
     98      */
     99     public synchronized String addApplicationListener(Bundle bundle, ListenerRegistration registration) {
    100         EventListener listener = null;
    101         try {
    102             listener = registration.getListenerClass().newInstance();
    103         } catch (Throwable e) {
    104             throw new IllegalArgumentException("Create listener instance error: " + registration.getListenerClass(), e);
    105         }
    106 
    107         return addApplicationListener(bundle, registration, listener);
    108     }
    109 
    110     /*
    111      * (non-Javadoc)
    112      * 
    113      * @see org.dbstar.osgi.web.register.ListenerService#addApplicationListener(org.osgi.framework.Bundle,
    114      * org.dbstar.osgi.web.register.ListenerRegistration, java.util.EventListener)
    115      */
    116     public synchronized String addApplicationListener(Bundle bundle, ListenerRegistration registration,
    117             EventListener listener) {
    118         String listenerName = getListenerName(bundle, listener);
    119 
    120         // 檢查listener是否已經注冊過
    121         if (nlMap.containsValue(listener) || nlMap.containsKey(listenerName)) {
    122             if (log != null) log.log(LogService.LOG_ERROR, "Listener already registered: " + listenerName);
    123             throw new IllegalArgumentException("Listener already registered: " + listenerName);
    124         }
    125 
    126         addApplicationListener(bundle.getBundleId(), listener, listenerName);
    127         return listenerName;
    128     }
    129 
    130     private void addApplicationListener(Long bundleId, EventListener listener, String listenerName) {
    131         boolean isApplicationListener = false;
    132 
    133         if (isEventListener(listener)) {
    134             Object[] listeners = context.getApplicationEventListeners();
    135             if (!inArray(listeners, listener)) {
    136                 context.setApplicationEventListeners(addToArray(listeners, listener));
    137                 isApplicationListener = true;
    138             }
    139         }
    140 
    141         if (isLifecycleListener(listener)) {
    142             Object[] listeners = context.getApplicationLifecycleListeners();
    143             if (!inArray(listeners, listener)) {
    144                 context.setApplicationLifecycleListeners(addToArray(listeners, listener));
    145                 isApplicationListener = true;
    146             }
    147         }
    148 
    149         if (isApplicationListener) {
    150             context.addApplicationListener(listenerName);
    151 
    152             List<String> nameList = bnsMap.get(bundleId);
    153             if (nameList == null) {
    154                 nameList = new ArrayList<String>();
    155                 bnsMap.put(bundleId, nameList);
    156             }
    157             nameList.add(listenerName);
    158             nlMap.put(listenerName, listener);
    159             nbMap.put(listenerName, bundleId);
    160 
    161             if (log != null) log.log(LogService.LOG_INFO, "Add ApplicationListener success: " + listenerName);
    162 
    163             // 必要的初始化
    164             if (listener instanceof ServletContextListener) {
    165                 try {
    166                     ServletContextEvent event = new ServletContextEvent(context.getServletContext());
    167                     ((ServletContextListener) listener).contextInitialized(event);
    168                 } catch (Throwable e) {
    169                     if (log != null) log.log(LogService.LOG_WARNING, "contextInitialized() error: " + listenerName, e);
    170                 }
    171             }
    172             if (listener instanceof HttpSessionListener) {
    173                 for (Session session : context.getManager().findSessions()) {
    174                     try {
    175                         HttpSessionEvent event = new HttpSessionEvent(session.getSession());
    176                         ((HttpSessionListener) listener).sessionCreated(event);
    177                     } catch (Throwable e) {
    178                         if (log != null) log.log(LogService.LOG_WARNING, "sessionCreated() error: " + listenerName, e);
    179                     }
    180                 }
    181             }
    182         }
    183     }
    184 
    185     /*
    186      * (non-Javadoc)
    187      * 
    188      * @see org.dbstar.osgi.web.register.ListenerService#removeApplicationListener(java.lang.String)
    189      */
    190     public synchronized void removeApplicationListener(String listenerName) {
    191         // 檢查listener是否已經注冊過
    192         if (!nlMap.containsKey(listenerName)) {
    193             if (log != null) log.log(LogService.LOG_WARNING, "Listener not register: " + listenerName);
    194             return;
    195         }
    196 
    197         removeApplicationListener(nbMap.get(listenerName), listenerName);
    198     }
    199 
    200     private void removeApplicationListener(Long bundleId, String listenerName) {
    201         boolean isApplicationListener = false;
    202 
    203         EventListener listener = nlMap.get(listenerName);
    204 
    205         if (isEventListener(listener)) {
    206             Object[] listeners = context.getApplicationEventListeners();
    207             if (inArray(listeners, listener)) {
    208                 context.setApplicationEventListeners(removeFromArray(listeners, listener));
    209                 isApplicationListener = true;
    210             }
    211         }
    212 
    213         if (isLifecycleListener(listener)) {
    214             Object[] listeners = context.getApplicationLifecycleListeners();
    215             if (inArray(listeners, listener)) {
    216                 context.setApplicationLifecycleListeners(removeFromArray(listeners, listener));
    217                 isApplicationListener = true;
    218             }
    219         }
    220 
    221         if (isApplicationListener) {
    222             context.removeApplicationListener(listenerName);
    223 
    224             List<String> nameList = bnsMap.get(bundleId);
    225             if (nameList != null) {
    226                 nameList.remove(listenerName);
    227                 if (nameList.isEmpty()) bnsMap.remove(bundleId);
    228             }
    229             nlMap.remove(listenerName);
    230             nbMap.remove(listenerName);
    231 
    232             if (log != null) log.log(LogService.LOG_INFO, "Remove ApplicationListener success: " + listenerName);
    233 
    234             // destroy
    235             if (listener instanceof ServletContextListener) {
    236                 try {
    237                     ServletContextEvent event = new ServletContextEvent(context.getServletContext());
    238                     ((ServletContextListener) listener).contextDestroyed(event);
    239                 } catch (Throwable e) {
    240                     if (log != null) log.log(LogService.LOG_WARNING, "contextDestroyed() error: " + listenerName, e);
    241                 }
    242             }
    243             if (listener instanceof HttpSessionListener) {
    244                 for (Session session : context.getManager().findSessions()) {
    245                     try {
    246                         HttpSessionEvent event = new HttpSessionEvent(session.getSession());
    247                         ((HttpSessionListener) listener).sessionDestroyed(event);
    248                     } catch (Throwable e) {
    249                         if (log != null) log
    250                                 .log(LogService.LOG_WARNING, "sessionDestroyed() error: " + listenerName, e);
    251                     }
    252                 }
    253             }
    254         }
    255     }
    256 
    257     private static boolean inArray(Object[] objects, Object object) {
    258         for (Object obj : objects) {
    259             if (obj == object) return true;
    260         }
    261         return false;
    262     }
    263 
    264     private static Object[] addToArray(Object[] objects, Object object) {
    265         Object[] newList = new Object[objects.length + 1];
    266         System.arraycopy(objects, 0, newList, 0, objects.length);
    267         newList[objects.length] = object;
    268         return newList;
    269     }
    270 
    271     private static Object[] removeFromArray(Object[] objects, Object object) {
    272         int n = -1;
    273         for (int i = 0; i < objects.length; i++) {
    274             if (objects[i] == object) {
    275                 n = i;
    276                 break;
    277             }
    278         }
    279         if (n < 0return objects;
    280 
    281         // Remove the specified constraint
    282         int j = 0;
    283         Object results[] = new Object[objects.length - 1];
    284         for (int i = 0; i < objects.length; i++) {
    285             if (i != n) results[j++= objects[i];
    286         }
    287         return results;
    288     }
    289 
    290     private String getListenerName(Bundle bundle, EventListener listener) {
    291         Class<? extends EventListener> clazz = listener.getClass();
    292         String className = clazz.getName();
    293         if (bundle != null) className = "bundle@" + bundle.getBundleId() + "@" + className + "@" + listener.hashCode();
    294         return className;
    295     }
    296 
    297     private boolean isEventListener(EventListener listener) {
    298         return (listener instanceof ServletContextAttributeListener)
    299                 || (listener instanceof ServletRequestAttributeListener)
    300                 || (listener instanceof ServletRequestListener) || (listener instanceof HttpSessionAttributeListener);
    301     }
    302 
    303     private boolean isLifecycleListener(EventListener listener) {
    304         return (listener instanceof ServletContextListener) || (listener instanceof HttpSessionListener);
    305     }
    306 
    307     private synchronized void destroy() {
    308         Set<Long> bundleSet = bnsMap.keySet();
    309         for (Long bundleId : bundleSet.toArray(new Long[bundleSet.size()])) {
    310             List<String> nameList = bnsMap.get(bundleId);
    311             for (String listenerName : nameList.toArray(new String[nameList.size()])) {
    312                 removeApplicationListener(bundleId, listenerName);
    313             }
    314         }
    315     }
    316 }
    在這個實現類中,我還實現了一個BundleListener接口,這樣就可以在某個bundle stop的時候,順便把這個bundle所注冊的所有的Listener都給注銷掉,這樣就不用在bundle內仔細的維護Listener的注冊和注銷了,也算是一個小小的便利吧,當然了,對于在Component內部注冊的Listener,還是不能在Component銷毀的時候自動實行反注冊,需要自己維護。


    最后,再給一個使用ListenerService的例子吧:
    listener.xml:
    1 <?xml version="1.0" encoding="UTF-8"?>
    2 <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="testListener" xsi:schemaLocation="http://www.osgi.org/xmlns/scr/v1.1.0 http://www.osgi.org/xmlns/scr/v1.1.0/scr.xsd">
    3   <implementation class="testlistener.TestListener"/>
    4   <reference cardinality="1..1" interface="org.dbstar.osgi.web.register.ListenerService" name="ListenerService" policy="static"/>
    5   <reference bind="bindLog" cardinality="0..1" interface="org.osgi.service.log.LogService" name="LogService" policy="static" unbind="unbindLog"/>
    6 </scr:component>

     1 package testlistener;
     2 
     3 import javax.servlet.ServletContextEvent;
     4 import javax.servlet.ServletContextListener;
     5 import javax.servlet.ServletRequestEvent;
     6 import javax.servlet.ServletRequestListener;
     7 
     8 import org.dbstar.osgi.web.register.ListenerRegistration;
     9 import org.dbstar.osgi.web.register.ListenerService;
    10 import org.osgi.framework.Bundle;
    11 import org.osgi.service.component.ComponentContext;
    12 import org.osgi.service.log.LogService;
    13 
    14 public class TestListener implements ServletRequestListener, ServletContextListener {
    15     private LogService log;
    16     private String listenerName;
    17 
    18     protected void activate(ComponentContext context) {
    19         Bundle bundle = context.getBundleContext().getBundle();
    20         ListenerService service = (ListenerService) context.locateService("ListenerService");
    21         listenerName = service.addApplicationListener(bundle, new ListenerRegistration(TestListener.class), this);
    22     }
    23 
    24     protected void deactivate(ComponentContext context) {
    25         ListenerService service = (ListenerService) context.locateService("ListenerService");
    26         if (listenerName != null) service.removeApplicationListener(listenerName);
    27     }
    28 
    29     protected void bindLog(LogService log) {
    30         this.log = log;
    31     }
    32 
    33     protected void unbindLog(LogService log) {
    34         if (this.log == log) this.log = null;
    35     }
    36 
    37     public void requestDestroyed(ServletRequestEvent sre) {
    38         if (log != null) log.log(LogService.LOG_INFO, "requestDestroyed(" + sre + ")");
    39     }
    40 
    41     public void requestInitialized(ServletRequestEvent sre) {
    42         if (log != null) log.log(LogService.LOG_INFO, "requestInitialized(" + sre + ")");
    43     }
    44 
    45     public void contextDestroyed(ServletContextEvent sce) {
    46         if (log != null) log.log(LogService.LOG_INFO, "contextDestroyed(" + sce + ")");
    47     }
    48 
    49     public void contextInitialized(ServletContextEvent sce) {
    50         if (log != null) log.log(LogService.LOG_INFO, "contextInitialized(" + sce + ")");
    51     }
    52 }








    posted on 2010-04-02 18:47 dbstar 閱讀(3664) 評論(2)  編輯  收藏 所屬分類: OSGi

    評論

    # re: 打造一個基于OSGi的Web Application——使用Tomcat原生API動態管理Listener  回復  更多評論   

    實現WEB容器的原生API的方案工作量有點大啊,不知道有沒有下文。。。
    2010-05-26 11:55 | hesy

    # re: 打造一個基于OSGi的Web Application——使用Tomcat原生API動態管理Listener[未登錄]  回復  更多評論   

    OSGi最成熟、最NB的開源開發平臺JXADF。
    歡迎訪問:http://osgi.jxtech.net
    2015-11-05 14:09 | Java Fans
    主站蜘蛛池模板: 33333在线亚洲| 久久国产精品免费一区二区三区| 永久免费无码网站在线观看| 欧洲精品码一区二区三区免费看| 亚洲AV成人无码久久精品老人 | 1000部禁片黄的免费看| 久久亚洲色WWW成人欧美| 亚洲国产精品成人精品无码区| 无码国产精品一区二区免费式直播| 人人爽人人爽人人片av免费| 亚洲精品美女视频| 亚洲av无码专区在线观看素人| 一级做a爰全过程免费视频| 精品国产_亚洲人成在线| 夜夜亚洲天天久久| 国产伦精品一区二区三区免费下载 | 亚洲一区精品无码| 免费高清在线影片一区| 一级做a爰全过程免费视频| 男女作爱免费网站| 亚洲色图激情文学| 亚洲AV无码国产精品麻豆天美 | xvideos亚洲永久网址| 黄色成人免费网站| 亚洲阿v天堂在线2017免费| 亚洲kkk4444在线观看| 亚洲天堂中文资源| 亚洲色欲久久久综合网| 四虎影视精品永久免费| 在线观看成人免费视频不卡| 免费精品99久久国产综合精品| 婷婷亚洲综合一区二区| 亚洲AV男人的天堂在线观看| 亚洲黑人嫩小videos| 国产精品亚洲аv无码播放| 国产免费黄色大片| 一二三四视频在线观看中文版免费 | 亚洲av无码成人影院一区| 666精品国产精品亚洲| 国产精品亚洲一区二区三区在线| 亚洲午夜爱爱香蕉片|