    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17
    18  package javax.jdo;
    19
    20  import java.lang.reflect.InvocationHandler;
    21  import java.lang.reflect.Method;
    22  import java.lang.reflect.Proxy;
    23
    24  import javax.jdo.spi.PersistenceCapable;
    25
    26  import javax.jdo.util.AbstractTest;
    27  import javax.jdo.util.BatchTestRunner;
    28
    29  /*
    30   * ObjectStateTest.java
    31   * This test class verifies the proper returned ObjectState for
    32   * each life cycle state. See Table 3 in section 7.4.
    33   *
    34   * @since 2.1
    35   */
    36  public class ObjectStateTest extends AbstractTest {
    37
    38      static final int PERSISTENT = 1;
    39      static final int TRANSACTIONAL = 2;
    40      static final int DIRTY = 4;
    41      static final int NEW = 8;
    42      static final int DELETED = 16;
    43      static final int DETACHED = 32;
    44
    45      private static final Method jdoIsPersistent = getDeclaredMethod(
    46              PersistenceCapable.class,
    47              "jdoIsPersistent",
    48              null);
    49      private static final Method jdoIsTransactional = getDeclaredMethod(
    50              PersistenceCapable.class,
    51              "jdoIsTransactional",
    52              null);
    53      private static final Method jdoIsDirty = getDeclaredMethod(
    54              PersistenceCapable.class,
    55              "jdoIsDirty",
    56              null);
    57      private static final Method jdoIsNew = getDeclaredMethod(
    58              PersistenceCapable.class,
    59              "jdoIsNew",
    60              null);
    61      private static final Method jdoIsDeleted = getDeclaredMethod(
    62              PersistenceCapable.class,
    63              "jdoIsDeleted",
    64              null);
    65      private static final Method jdoIsDetached = getDeclaredMethod(
    66              PersistenceCapable.class,
    67              "jdoIsDetached",
    68              null);
    69
    70      /** */
    71      public static void main(String args[]) {
    72          BatchTestRunner.run(ObjectStateTest.class);
    73      }
    74
    75      public void testNull() {
    76          PersistenceCapable mock = null;
    77          assertObjectState("null", null, mock);
    78      }
    79
    80      public void testTransient() {
    81          PersistenceCapable mock = newMock(0);
    82          assertObjectState("transient", ObjectState.TRANSIENT, mock);
    83      }
    84
    85      public void testTransientClean() {
    86          PersistenceCapable mock = newMock(TRANSACTIONAL);
    87          assertObjectState("transient-clean", ObjectState.TRANSIENT_CLEAN, mock);
    88      }
    89
    90      public void testTransientDirty() {
    91          PersistenceCapable mock = newMock(TRANSACTIONAL+DIRTY);
    92          assertObjectState("transient-dirty", ObjectState.TRANSIENT_DIRTY, mock);
    93      }
    94
    95      public void testPersistentNew() {
    96          PersistenceCapable mock = newMock(PERSISTENT+TRANSACTIONAL+NEW+DIRTY);
    97          assertObjectState("persistent-new", ObjectState.PERSISTENT_NEW, mock);
    98      }
    99
    100     public void testPersistentNontransactional() {
    101         PersistenceCapable mock = newMock(PERSISTENT);
    102         assertObjectState("persistent-nontransactional", ObjectState.HOLLOW_PERSISTENT_NONTRANSACTIONAL, mock);
    103     }
    104
    105     public void testPersistentNontransactionalDirty() {
    106         PersistenceCapable mock = newMock(PERSISTENT+DIRTY);
    107         assertObjectState("persistent-nontransactional-dirty", ObjectState.PERSISTENT_NONTRANSACTIONAL_DIRTY, mock);
    108     }
    109
    110     public void testPersistentClean() {
    111         PersistenceCapable mock = newMock(PERSISTENT+TRANSACTIONAL);
    112         assertObjectState("persistent-clean", ObjectState.PERSISTENT_CLEAN, mock);
    113     }
    114
    115     public void testPersistentDirty() {
    116         PersistenceCapable mock = newMock(PERSISTENT+TRANSACTIONAL+DIRTY);
    117         assertObjectState("persistent-dirty", ObjectState.PERSISTENT_DIRTY, mock);
    118     }
    119
    120     public void testPersistentDeleted() {
    121         PersistenceCapable mock = newMock(PERSISTENT+TRANSACTIONAL+DIRTY+DELETED);
    122         assertObjectState("persistent-deleted", ObjectState.PERSISTENT_DELETED, mock);
    123     }
    124
    125     public void testPersistentNewDeleted() {
    126         PersistenceCapable mock = newMock(PERSISTENT+TRANSACTIONAL+NEW+DIRTY+DELETED);
    127         assertObjectState("persistent-new-deleted", ObjectState.PERSISTENT_NEW_DELETED, mock);
    128     }
    129
    130     public void testDetachedClean() {
    131         PersistenceCapable mock = newMock(DETACHED);
    132         assertObjectState("detached-clean", ObjectState.DETACHED_CLEAN, mock);
    133     }
    134
    135     public void testDetachedDirty() {
    136         PersistenceCapable mock = newMock(DETACHED+DIRTY);
    137         assertObjectState("detached-dirty", ObjectState.DETACHED_DIRTY, mock);
    138     }
    139
    140     private void assertObjectState(String string,
    141             ObjectState expected,
    142             PersistenceCapable pc) {
    143         ObjectState actual = JDOHelper.getObjectState(pc);
    144         // test for == here because enums should be singleton
    145         if (actual == expected)
    146             return;
    147         fail("ObjectState failure for " + string + NL +
    148                 "expected: " + expected +
    149                 ", actual: " + actual);
    150     }
    151
    152     /**
    153      * Construct a new mock instance of PersistenceCapable that responds
    154      * to methods jdoIsXXX by returning the bit value of its constructor
    155      * masked with the value of XXX.
    156      * @param i the sum of bit masks representing the life cycle state
    157      * @return a mock instance of PersistenceCapable
    158      */
    159     private PersistenceCapable newMock(final int i) {
    160         return (PersistenceCapable)
    161             Proxy.newProxyInstance(
    162                 PersistenceCapable.class.getClassLoader(),
    163                 new Class[] {PersistenceCapable.class},
    164                 new MockInvocationHandler(i));
    165     }
    166
    167     private class MockInvocationHandler implements InvocationHandler {
    168         /** States is the sum of all life cycle interrogatives.
    169          */
    170         private int states;
    171
    172         /**
    173          * Constructs an invocation handler with the specified bit fields set
    174          * according to the sum of values of PERSISTENT, TRANSACTIONAL, DIRTY,
    175          * NEW, DELETED, and DETACHED.
    176          * @param i the bit field values for the life cycle interrogatives
    177          */
    178         private MockInvocationHandler(int i) {
    179             states = i;
    180         }
    181
    182         /**
    183          *
    184          * @param object the PersistenceCapable instance
    185          * @param method the method being invoked
    186          * @param parameters parameters (should be null)
    187          * @throws java.lang.Throwable unused
    188          * @return for jdoIsXXX methods only, returns whether the
    189          * bit field selected by the method is set in the
    190          * mock handler
    191          */
    192         public Object invoke(Object object, Method method, Object[] parameters)
    193                 throws Throwable {
    194             if (method.equals(jdoIsPersistent)) {
    195                 return (0 != (states & PERSISTENT));
    196             }
    197             if (method.equals(jdoIsTransactional)) {
    198                 return (0 != (states & TRANSACTIONAL));
    199             }
    200             if (method.equals(jdoIsDirty)) {
    201                 return (0 != (states & DIRTY));
    202             }
    203             if (method.equals(jdoIsNew)) {
    204                 return (0 != (states & NEW));
    205             }
    206             if (method.equals(jdoIsDeleted)) {
    207                 return (0 != (states & DELETED));
    208             }
    209             if (method.equals(jdoIsDetached)) {
    210                 return (0 != (states & DETACHED));
    211             }
    212             fail("Unexpected method called: " + method.getName());
    213             return Boolean.FALSE; // not reached
    214         }
    215     }
    216
    217     private static Method getDeclaredMethod
    218             (Class clazz, String methodName, Class[] parameters) {
    219         try {
    220             Method result = clazz.getDeclaredMethod(methodName, parameters);
    221             return result;
    222         } catch (Exception ex) {
    223             // human-readable class.methodName(parameter[,parameter])
    224             StringBuffer sb = new StringBuffer(methodName);
    225             String delimiter = "(";
    226             for (Class parameter: parameters) {
    227                 sb.append(delimiter);
    228                 sb.append(parameter.getName());
    229                 delimiter = ",";
    230             }
    231             sb.append(")");
    232             throw new RuntimeException
    233                 ("getDeclaredMethod for " + clazz.getName() + "." +
    234                     sb + " threw..." + ex);
    235         }
    236     }
    237 }