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

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

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

    jinfeng_wang

    G-G-S,D-D-U!

    BlogJava 首頁 新隨筆 聯(lián)系 聚合 管理
      400 Posts :: 0 Stories :: 296 Comments :: 0 Trackbacks
    Dynamic Delegation and Its Applicationsby Lu Jian
    11/17/2004

    The Proxy pattern is an important and widely used design pattern in object-oriented programming. Do you ever use Proxy in Java since its introduction in JDK 1.3? A dynamic proxy class is a class that implements a list of interfaces specified at runtime. An implementation for the proxy's behavior can be provided at runtime through an InvocationHandler. So Proxy is an important class in Java's reflection package, and is widely used in many Java applications.

    One limitation of Proxy is that it can only accept interfaces. In some circumstances, you need to apply the Proxy pattern not only to interfaces, but also to abstract classes, and even concrete classes.

    This article introduces Dynamic Delegation, which can create delegation for both interfaces and classes at runtime.

    Proxy Overview

    In JDK 1.3, the Proxy class was added to java.lang.reflect. It can create a concrete class that implements all of the specified interfaces at runtime. The dynamically generated class redirects all of the method calls defined in the interfaces to an InvocationHandler.

    Given two interfaces, Idel1 and Idel2, Proxy will create a IdelProxy class as the proxy of these two interfaces (I use IdelProxy as the generated proxy class name for convenience). Figure 1 shows this arrangement.

    Class Diagram of IdelProxy
    Figure 1. Class diagram of IdelProxy

    Below is the related code snippet.

    
        Class clazz = Proxy.getProxyClass(
             Idel1.class.getClassLoader(), 
             new Class[] { Idel1.class, Idel2.class });
    

    Delegation Versus Proxy

    Proxy only works for interfaces. What if we need it to work for both classes and interfaces? The Dunamis project on java.net introduces Delegation as an alternative to Proxy. Delegation uses a different approach than Proxy.

    Given a class named TestBean, the delegation class TestBeanDelegation's class diagram is shown in Figure 2.

    Class Diagram of TestBeanDelegation
    Figure 2. Class diagram of TestBeanDelegation (click for full-size image)

    TestBeanDelegation implements the Delegation interface and extends the TestBean class. It also contains references to TestBean and DelegationInvocationHandler. All of the method calls on TestBeanDelegation will be delegated to them.

    Take getName() as an example. The chart in Figure 3 illustrates the sequence of the method call.

    Sequence Chart of TestBeanDelegation.getName()
    Figure 3. Sequence chart of TestBeanDelegation.getName() (click for full-size image)

    The related pseudocode is:

    
    //The delegation class is a sub-class of the class to be delegated
    public class TestBeanDelegation extends TestBean
            implements Delegation {
        //The object to be delegated
        TestBean bean;
        //The invocation handler
        DelegationInvocationHandler handler;
        ...
        static Method m0 = null;
        ...
    
        static {
            ...
            try {
                m0 = TestBean.class.getMethod("getName",
                                     new Class[] {});
            } catch (Exception exception) {
            }
            ...
        }
    
        public TestBeanDelegation(Object bean) {
            this.bean = (TestBean)bean;
        }
    
        public String getName() {
            boolean goon = true;
            String ret = null;
            Throwable t = null;
            try {
                goon = handler.invokeBefore(bean,
                            m0, new Object[] {});
                if (goon)
                    try {
                        ret = bean.getName();
                    } catch (Throwable throwable) {
                        t = throwable;
                    }
                if (t != null)
                    ret = handler.invokeAfterException(bean,
                                m0, new Object[] {}, t);
                else
                    ret = handler.invokeAfter(bean,
                                m0, new Object[] { name }, null);
                return ret;
            } catch (RuntimeException e) {
                throw e;
            } catch (Error e) {
                throw e;
            } catch (Throwable throwable) {
                throw new UndeclaredThrowableException(throwable);
            }
        }
    }
    

    An Introduction to Dynamic Delegation

    Dynamic Delegation is based on the Jakarta Byte-Code Engineering Library (BCEL). It can analyze the existing class and generate a delegation class in byte code for an interface, abstract class, or even a concrete class at runtime.

    The interface/class to be delegated should meet the following conditions:

    • Dynamic Delegation can accept one class at most, but can accept multiple interfaces.

      This limitation is based on Java's single inheritance model. One Java class can have at most one superclass. Since the generated delegation class takes the given class as its superclass, it is illegal to specify more than one class. If no class specified, the default superclass is Object.

    • The input class should have a default constructor with a public or protected modifier.

      The delegation class will call the superclass' default constructor in its own constructor.

    • The input class cannot be final, and should be visible to the caller.

      The proxy class generated by Proxy is final. It will not be accepted by Dynamic Delegation.

    • Dynamic Delegation cannot accept any class that implements the Delegation interface.

      Since it is already a delegation class, why would you need to delegate it again?

    The generated delegation class has the following characteristics:

    • It is generated on the fly and has no class file.
    • It implements all of the given interfaces and extends the given class.
    • It also implements the Delegation interface.
    • It has a constructor that accepts an Object instance as a parameter.

    DelegationGenerator is the main class of Dynamic Delegation. A client can use it to generate a delegation class/object for a specific class/interface/object. DelegationInvocationHandler is an interface defining all of the delegation behaviors and is expected to be implemented by the client's developer. The delegation object can use the _getInvocationHandler() and _setInvocationHandler() methods defined in Delegation to access the DelegationInvocationHandler instance in the delegation object.

    Exercise 1. Create a Delegation Class for a Concrete Class

    Suppose there is a concrete class named ConcreteClass:

    
    //ConcreteClass.java
    package org.jingle.util.dydelegation.sample;
    
    public class ConcreteClass {
        public void hello() {
            System.out.println("Hello from ConcreteClass");
        }
        
        protected void hello2() {
            System.out.println("Hello again from ConcreteClass");
        }
    }
    

    The following code generates a delegation class for ConcreteClass.

    
    //ConcreteClassTest.java
    package org.jingle.util.dydelegation.sample;
    
    import org.jingle.util.dydelegation.DelegationGenerator;
    
    public class ConcreteClassTest {
        public static void main(String[] args) {
            Class clazz = DelegationGenerator
                    .getDelegationClass(new Class[] { ConcreteClass.class });
            System.out.println("Delegation class name = " +
                                clazz.getName());
            System.out.println(
                ConcreteClass.class.isAssignableFrom(clazz));
        }
    }
    

    The output shows:

    
    Delegation class name =
    org.jingle.util.dydelegation.sample.ConcreteClass_Delegation_0
    true
    

    DelegationGenerator.getDelegationClass() accepts a class array as parameter and return a Java Class that extends/implements the given class/interfaces. By default, the generated delegation class is in the same package as the class to be delegated.

    The delegation class can be instantiated as below:

    
    //object to be delegated
    Object obj = ...; 
    //some concrete invocation handler instance
    DelegationInvocationHandler h = ...; 
    
    Constructor c = clazz.getConstructor(new Class[] { Object.class });
    Object inst = c.newInstance(new Object[] {obj});
    ((Delegation) inst)._setInvocationHandler(h);
    

    Exercise 2. Create a Delegation Class for an Abstract Class

    DelegationGenerator can also generate a concrete delegation class for an abstract class.

    
    //AbstractClass.java
    package org.jingle.util.dydelegation.sample;
    
    public abstract class AbstractClass {
        public abstract void wave();
    }
    
    
    //AbstractClassTest.java
    package org.jingle.util.dydelegation.sample;
    
    import java.lang.reflect.Modifier;
    
    import org.jingle.util.dydelegation.DelegationGenerator;
    
    public class AbstractClassTest {
        public static void main(String[] args) {
            Class clazz = DelegationGenerator
                    .getDelegationClass(new Class[] { AbstractClass.class });
            System.out.println("Delegation class name = " +
                clazz.getName());
            System.out.println(
                Modifier.isAbstract(clazz.getModifiers()));
        }
    }
    

    Output:

    
    Delegation class name = 
    org.jingle.util.dydelegation.sample.AbstractClass_Delegation_0
    false
    

    The generated delegation class is a concrete class instead of an abstract class.

    Exercise 3. Create a Delegation Class for Both a Class and Multiple Interfaces

    DelegationGenerator.getDelegationClass() can accept a class and multiple interfaces simultaneously to generate a delegation class to delegate the given class and interfaces. Duplicate interfaces will be eliminated.

    
    //Idel1.java
    package org.jingle.util.dydelegation.sample.bean;
    
    public interface Idel1 {
        public void idel1();
    }
    
    
    //Idel2.java
    package org.jingle.util.dydelegation.sample.bean;
    
    public interface Idel2 {
        public void idel2();
    }
    
    
    //ComplexClassTest.java
    package org.jingle.util.dydelegation.sample;
    
    import org.jingle.util.dydelegation.DelegationGenerator;
    import org.jingle.util.dydelegation.sample.bean.Idel1;
    import org.jingle.util.dydelegation.sample.bean.Idel2;
    
    public class ComplexClassTest {
        public static void main(String[] args) {
            Class clazz = DelegationGenerator.getDelegationClass(new Class[] {
                    ConcreteClass.class, Idel1.class, Idel2.class });
            System.out.println(
                Idel1.class.isAssignableFrom(clazz));
            System.out.println(
                Idel2.class.isAssignableFrom(clazz));
            System.out.println(
                ConcreteClass.class.isAssignableFrom(clazz));
        }
    }
    

    Output:

    
    true
    true
    true
    

    The generated delegation class extends the given class ConcreteClass and implements all of the given interfaces: Idel1 and Idel2.

    Exercise 4. Create a Delegation Object for a Specific Object

    DelegationGenerator can generate a delegation object directly, according to a specific object to be delegated.

    
    // ConcreteClassTest2.java
    package org.jingle.util.dydelegation.sample;
    
    import java.lang.reflect.Method;
    
    import org.jingle.util.dydelegation.DelegationGenerator;
    import org.jingle.util.dydelegation.DelegationInvocationHandler;
    import org.jingle.util.dydelegation.DummyInvocationHandler;
    
    public class ConcreteClassTest2 {
        public static void main(String[] args) {
            ConcreteClass inst = new ConcreteClass();
            DelegationInvocationHandler handler =
                new SimpleHandler();
            ConcreteClass delegation = (ConcreteClass)
                DelegationGenerator.newDelegationInstance(inst, handler);
            delegation.hello();
            delegation.hello2();
            System.out.println(delegation.toString());
        }
    }
    
    class SimpleHandler extends DummyInvocationHandler {
        public boolean invokeBefore(Object bean,
                                    Method method, Object[] args)
                throws Throwable {
            System.out.println("Interrupted by SimpleHandler");
            return super.invokeBefore(bean, method, args);
        }
    }
    

    Output:

    
    Interrupted by SimpleHandler
    Hello from ConcreteClass
    Hello again from ConcreteClass
    Interrupted by SimpleHandler
    org.jingle.util.dydelegation.sample.ConcreteClass@ef5502
    

    DummyInvocationHandler is a dummy implementation of DelegationInvocationHandler. It always returns true in invokeBefore(), returns the input result directly in invokeAfter(), and throws the input throwable directly in invokeAfterException(). The delegation object with DummyInvocationHandler has same behavior as the object to be delegated.

    DelegationGenerator.newDelegationInstance() accepts an object and an DelegationInvocationHandler instance as parameters. It returns a delegation object to delegate the given object.

    All of the methods called on the delegation object will be delegated to the DelegationInvocationHandler instance, except:

    • Methods without a public modifier.
    • Methods with a final modifier.
    • Methods with a static modifier.
    • Methods declared in the Object class, other than hashCode(), equals(), and toString().


    Exercise 5. Create Delegation Object for the Object of a Java Core Class

    Did you ever want to delegate an object of an existing Java core class? Delegate it as usual.

    
    //DateTest.java
    package org.jingle.util.dydelegation.sample;
    
    import java.lang.reflect.Method;
    import java.util.Date;
    
    import org.jingle.util.dydelegation.DelegationGenerator;
    import org.jingle.util.dydelegation.DelegationInvocationHandler;
    import org.jingle.util.dydelegation.DummyInvocationHandler;
    
    public class DateTest {
        public static void main(String[] args) {
            Date date = new Date();
            DelegationInvocationHandler handler = 
                new DateClassHandler();
            Date delegation = (Date) DelegationGenerator
                    .newDelegationInstance(date, handler);
            System.out.println("Delegation class = " +
                delegation.getClass().getName());
            System.out.println("True date = " +
                date.getTime());
            System.out.println("Delegation date = " +
                delegation.getTime());
        }
    }
    
    class DateClassHandler extends DummyInvocationHandler {
        public Object invokeAfter(Object bean,
                        Method method, Object[] args,
                        Object result) throws Throwable {
            if (method.getName().equals("getTime")) {
                return new Long(((Long)result).longValue() - 1000);
            }
            return super.invokeAfter(bean, method, args, result);
        }
    }
    

    Output:

    
    Delegation class = org.jingle.util.dydelegation.Date_Delegation_0
    True date = 1099380377665
    Delegation date = 1099380376665
    
    

    When creating a delegation class for a Java core class, the delegation class will not be in the same package as the Java core class, because the Java security model does not allow a user-defined ClassLoader to define a class in a package starting with java.

    DateClassHandler catches the getTime() method call in invokeAfter(), and makes the return value 1000 less than the normal return value.

    Advanced Usage

    Exercise 6. Simulate Proxy Behavior

    Can Dynamic Delegation do what Proxy does? Absolutely! Dynamic Delegation covers the functions of Proxy. Given a proper delegation handler, it can simulate the behavior of a Java Proxy.

    
    // ProxyTest.java
    package org.jingle.util.dydelegation.sample;
    
    import java.lang.reflect.Method;
    
    import org.jingle.util.dydelegation.DelegationGenerator;
    import org.jingle.util.dydelegation.DelegationInvocationHandler;
    import org.jingle.util.dydelegation.DummyInvocationHandler;
    import org.jingle.util.dydelegation.sample.bean.Idel1;
    import org.jingle.util.dydelegation.sample.bean.Idel2;
    
    public class ProxyTest {
        public static void main(String[] args) {
            DelegationInvocationHandler handler = new ProxyHandler();
            Object delegation =
                DelegationGenerator.newDelegationInstance(null,
                    new Class[] { Idel1.class, Idel2.class },
                    null, handler);
            ((Idel1) delegation).idel1();
            ((Idel2) delegation).idel2();
        }
    }
    
    class ProxyHandler extends DummyInvocationHandler {
        public boolean invokeBefore(Object bean,
                Method method, Object[] args)
                throws Throwable {
            return false;
        }
    
        public Object invokeAfter(Object bean, 
                Method method, Object[] args,
                Object result) throws Throwable {
            String name = method.getName();
            if (name.equals("idel1"))
                System.out.println("Hello from idel1");
            else if (name.equals("idel2"))
                System.out.println("Hello from idel2");
            return super.invokeAfter(bean, method, args, result);
        }
    }
    

    Output:

    
    Hello from idel1
    Hello from idel2
    

    ProxyHandler returns false in invokeBefore(), which means all of the method calls on the delegation object will not be delegated to the original object. It uses invokeAfter() to define the delegation behavior as being what Proxy does.

    DelegationGenerator.newDelegationInstance() has another version. It contains four arguments:

    • The Object to be delegated.

      This can be null. If it is not null, it must be an instance of all of the given classes and interfaces.

    • An array of Class to be delegated.

      This can contain multiple interfaces and, at most, one class.

    • Delegation class name.

      If null, a system-generated name will be provided.

    • A DelegationInvocationHandler instance, which is used to define the delegation's behavior.

    From the output, we can see that the delegation object is an instance of both Idel1 and Idel2. Its behavior is just what is defined in the handler.

    Exercise 7. Partial Delegation

    Until now, we've delegated all of the functions of the specific object. How about just delegating part of the object's functions?

    
    //MyDate.java
    package org.jingle.util.dydelegation.sample.bean;
    
    import java.util.Date;
    
    public class MyDate extends Date implements Idel1, Idel2 {
        public void idel1() {
        }
    
        public void idel2() {
        }
    }
    
    
    // MyDateTest.java
    package org.jingle.util.dydelegation.sample;
    
    import java.util.Date;
    
    import org.jingle.util.dydelegation.DelegationGenerator;
    import org.jingle.util.dydelegation.DelegationInvocationHandler;
    import org.jingle.util.dydelegation.DummyInvocationHandler;
    import org.jingle.util.dydelegation.sample.bean.Idel1;
    import org.jingle.util.dydelegation.sample.bean.Idel2;
    import org.jingle.util.dydelegation.sample.bean.MyDate;
    
    public class MyDateTest {
        public static void main(String[] args) {
            MyDate inst = new MyDate();
            DelegationInvocationHandler handler =
                new DummyInvocationHandler();
            Object delegation = 
                DelegationGenerator.newDelegationInstance(inst,
                    new Class[] { Idel1.class, Idel2.class },
                    null, handler);
            System.out.println(delegation instanceof Idel1);
            System.out.println(delegation instanceof Idel2);
            System.out.println(delegation instanceof Date);
        }
    }
    

    Output:

    
    true
    true
    false
    

    MyDate extends Date and implements the Idel1 and Idel2 interfaces. DelegationGenerator.newDelegationInstance() uses a MyDate instance as the object instance to be delegated, and limits the delegation scope in Idel1 and Idel2. In other words, the generated delegation object is an instance of Idel1 and Idel2, but not an instance of Date.

    Conclusion

    The Dunamis project introduces Dynamic Delegation to extend the function of the Java Proxy reflection utility. It can generate delegation for both classes and interfaces at runtime. This article introduces Dynamic Delegation in brief with simple examples. In the real world, Dynamic Delegation can be used in many areas, such as mock objects in unit testing, Java GUI MVC framework, and more.

    Reference

    Lu Jian is a senior Java architect/developer with four years of Java development experience.

    Exercise 1. Create a Delegation Class for a Concrete Class

    Suppose there is a concrete class named ConcreteClass:

    
    //ConcreteClass.java
    package org.jingle.util.dydelegation.sample;
    
    public class ConcreteClass {
        public void hello() {
            System.out.println("Hello from ConcreteClass");
        }
        
        protected void hello2() {
            System.out.println("Hello again from ConcreteClass");
        }
    }
    

    The following code generates a delegation class for ConcreteClass.

    
    //ConcreteClassTest.java
    package org.jingle.util.dydelegation.sample;
    
    import org.jingle.util.dydelegation.DelegationGenerator;
    
    public class ConcreteClassTest {
        public static void main(String[] args) {
            Class clazz = DelegationGenerator
                    .getDelegationClass(new Class[] { ConcreteClass.class });
            System.out.println("Delegation class name = " +
                                clazz.getName());
            System.out.println(
                ConcreteClass.class.isAssignableFrom(clazz));
        }
    }
    

    The output shows:

    
    Delegation class name =
    org.jingle.util.dydelegation.sample.ConcreteClass_Delegation_0
    true
    

    DelegationGenerator.getDelegationClass() accepts a class array as parameter and return a Java Class that extends/implements the given class/interfaces. By default, the generated delegation class is in the same package as the class to be delegated.

    The delegation class can be instantiated as below:

    
    //object to be delegated
    Object obj = ...; 
    //some concrete invocation handler instance
    DelegationInvocationHandler h = ...; 
    
    Constructor c = clazz.getConstructor(new Class[] { Object.class });
    Object inst = c.newInstance(new Object[] {obj});
    ((Delegation) inst)._setInvocationHandler(h);
    

    Exercise 2. Create a Delegation Class for an Abstract Class

    DelegationGenerator can also generate a concrete delegation class for an abstract class.

    
    //AbstractClass.java
    package org.jingle.util.dydelegation.sample;
    
    public abstract class AbstractClass {
        public abstract void wave();
    }
    
    
    //AbstractClassTest.java
    package org.jingle.util.dydelegation.sample;
    
    import java.lang.reflect.Modifier;
    
    import org.jingle.util.dydelegation.DelegationGenerator;
    
    public class AbstractClassTest {
        public static void main(String[] args) {
            Class clazz = DelegationGenerator
                    .getDelegationClass(new Class[] { AbstractClass.class });
            System.out.println("Delegation class name = " +
                clazz.getName());
            System.out.println(
                Modifier.isAbstract(clazz.getModifiers()));
        }
    }
    

    Output:

    
    Delegation class name = 
    org.jingle.util.dydelegation.sample.AbstractClass_Delegation_0
    false
    

    The generated delegation class is a concrete class instead of an abstract class.

    Exercise 3. Create a Delegation Class for Both a Class and Multiple Interfaces

    DelegationGenerator.getDelegationClass() can accept a class and multiple interfaces simultaneously to generate a delegation class to delegate the given class and interfaces. Duplicate interfaces will be eliminated.

    
    //Idel1.java
    package org.jingle.util.dydelegation.sample.bean;
    
    public interface Idel1 {
        public void idel1();
    }
    
    
    //Idel2.java
    package org.jingle.util.dydelegation.sample.bean;
    
    public interface Idel2 {
        public void idel2();
    }
    
    
    //ComplexClassTest.java
    package org.jingle.util.dydelegation.sample;
    
    import org.jingle.util.dydelegation.DelegationGenerator;
    import org.jingle.util.dydelegation.sample.bean.Idel1;
    import org.jingle.util.dydelegation.sample.bean.Idel2;
    
    public class ComplexClassTest {
        public static void main(String[] args) {
            Class clazz = DelegationGenerator.getDelegationClass(new Class[] {
                    ConcreteClass.class, Idel1.class, Idel2.class });
            System.out.println(
                Idel1.class.isAssignableFrom(clazz));
            System.out.println(
                Idel2.class.isAssignableFrom(clazz));
            System.out.println(
                ConcreteClass.class.isAssignableFrom(clazz));
        }
    }
    

    Output:

    
    true
    true
    true
    

    The generated delegation class extends the given class ConcreteClass and implements all of the given interfaces: Idel1 and Idel2.

    Exercise 4. Create a Delegation Object for a Specific Object

    DelegationGenerator can generate a delegation object directly, according to a specific object to be delegated.

    
    // ConcreteClassTest2.java
    package org.jingle.util.dydelegation.sample;
    
    import java.lang.reflect.Method;
    
    import org.jingle.util.dydelegation.DelegationGenerator;
    import org.jingle.util.dydelegation.DelegationInvocationHandler;
    import org.jingle.util.dydelegation.DummyInvocationHandler;
    
    public class ConcreteClassTest2 {
        public static void main(String[] args) {
            ConcreteClass inst = new ConcreteClass();
            DelegationInvocationHandler handler =
                new SimpleHandler();
            ConcreteClass delegation = (ConcreteClass)
                DelegationGenerator.newDelegationInstance(inst, handler);
            delegation.hello();
            delegation.hello2();
            System.out.println(delegation.toString());
        }
    }
    
    class SimpleHandler extends DummyInvocationHandler {
        public boolean invokeBefore(Object bean,
                                    Method method, Object[] args)
                throws Throwable {
            System.out.println("Interrupted by SimpleHandler");
            return super.invokeBefore(bean, method, args);
        }
    }
    

    Output:

    
    Interrupted by SimpleHandler
    Hello from ConcreteClass
    Hello again from ConcreteClass
    Interrupted by SimpleHandler
    org.jingle.util.dydelegation.sample.ConcreteClass@ef5502
    

    DummyInvocationHandler is a dummy implementation of DelegationInvocationHandler. It always returns true in invokeBefore(), returns the input result directly in invokeAfter(), and throws the input throwable directly in invokeAfterException(). The delegation object with DummyInvocationHandler has same behavior as the object to be delegated.

    DelegationGenerator.newDelegationInstance() accepts an object and an DelegationInvocationHandler instance as parameters. It returns a delegation object to delegate the given object.

    All of the methods called on the delegation object will be delegated to the DelegationInvocationHandler instance, except:

    • Methods without a public modifier.
    • Methods with a final modifier.
    • Methods with a static modifier.
    • Methods declared in the Object class, other than hashCode(), equals(), and toString().
    posted on 2005-03-20 18:23 jinfeng_wang 閱讀(587) 評(píng)論(0)  編輯  收藏 所屬分類: Thinking
    主站蜘蛛池模板: 性做久久久久免费观看| 在线免费视频一区| 亚洲激情在线观看| 99视频全部免费精品全部四虎| 亚洲国产日产无码精品| 成人免费视频试看120秒| 免费国产va在线观看| 久久亚洲精品成人| 好吊妞在线成人免费| 午夜影院免费观看| 亚洲免费综合色在线视频| 亚洲毛片不卡av在线播放一区| 国产成人精品免费久久久久| 456亚洲人成影院在线观| 亚洲精品偷拍视频免费观看| 天天摸夜夜摸成人免费视频| 91九色老熟女免费资源站| 婷婷亚洲综合五月天小说在线| 亚洲一区二区三区在线观看精品中文| 99久热只有精品视频免费看| 色婷婷六月亚洲综合香蕉| 国产亚洲免费的视频看| 在线免费观看污网站| 黄色片在线免费观看 | 国产精品免费网站| 午夜免费啪视频在线观看| 日韩电影免费在线观看中文字幕| 精品无码国产污污污免费网站国产 | 国产成人免费永久播放视频平台| 免费在线看污视频| 亚洲精品人成网线在线播放va| 亚洲国产精华液网站w| 永久免费AV无码网站在线观看 | 国产亚洲av片在线观看16女人 | 91视频免费观看高清观看完整| 亚洲 日韩 色 图网站| 国产V亚洲V天堂无码久久久| 亚洲日韩欧洲乱码AV夜夜摸| 亚洲香蕉网久久综合影视| 亚洲线精品一区二区三区影音先锋| 亚洲伊人久久综合中文成人网 |