Try to determine the class context in which a #register(String) call was made.
()
| 1594 | was made. |
| 1595 | */ |
| 1596 | static Class<?> getCallingClass() { |
| 1597 | // This method makes the assumption that it is only called from register |
| 1598 | // and unregister methods of this class. It is further assumed, that |
| 1599 | // these two methods are called from a static initialized block or from |
| 1600 | // a method of the class to be registered. |
| 1601 | // |
| 1602 | // There are two approaches taken to find the right stack frame: |
| 1603 | // - on modern VMs the StackWalker API is used and the first two entries |
| 1604 | // are skipped. The stack at the time of calling is: |
| 1605 | // 0. Stackframe: #getCallingClass |
| 1606 | // 1. Stackframe: #register or #unregister |
| 1607 | // 2. Stackframe: method of outer caller |
| 1608 | // the last element is the right one |
| 1609 | // |
| 1610 | // - on VMs not supporting the StackWalker, the SecurityManager is used |
| 1611 | // to fetch the classes of the stack. The SecurityManager has |
| 1612 | // getClassContext which returns the classes of the callers. It is |
| 1613 | // protected though and needs to be exposed first. For this the stack |
| 1614 | // trace is: |
| 1615 | // 0. Stackframe: SecurityManagerExposer#getClassContext |
| 1616 | // 1. Stackframe: #getCallingClass |
| 1617 | // 2. Stackframe: #register or #unregister |
| 1618 | // 3. Stackframe: method of outer caller |
| 1619 | if (stackWalkerGetInstance != null) { |
| 1620 | try { |
| 1621 | Object walker = stackWalkerGetInstance.invoke(null, stackWalkerRetainClassReference); |
| 1622 | Class<?> caller = (Class<?>) stackWalkerWalk.invoke(walker, stackWalkerFilter); |
| 1623 | return caller; |
| 1624 | } catch (Throwable ex) { |
| 1625 | LOG.log(Level.WARNING, "Failed to invoke StackWalker#getInstance or StackWalker#walk", ex); |
| 1626 | } |
| 1627 | } |
| 1628 | |
| 1629 | if (securityManagerExposerConstructor != null) { |
| 1630 | Class<?>[] context = null; |
| 1631 | try { |
| 1632 | Object securityManagerExposer = securityManagerExposerConstructor.newInstance(); |
| 1633 | context = (Class<?>[]) securityManagerGetClassContext.invoke(securityManagerExposer); |
| 1634 | } catch (Throwable ex) { |
| 1635 | LOG.log(Level.WARNING, "Failed to invoke SecurityManagerExposer#<init> or SecurityManagerExposer#getClassContext", ex); |
| 1636 | } |
| 1637 | |
| 1638 | if (context == null) { |
| 1639 | throw new IllegalStateException("The SecurityManager implementation on this platform is broken; you must explicitly provide the class to register"); |
| 1640 | } |
| 1641 | if (context.length < 4) { |
| 1642 | throw new IllegalStateException("This method must be called from the static initializer of a class"); |
| 1643 | } |
| 1644 | return context[3]; |
| 1645 | } |
| 1646 | |
| 1647 | throw new IllegalStateException("Neither the StackWalker, nor the SecurityManager based getCallingClass implementation are useable; you must explicitly provide the class to register"); |
| 1648 | } |
| 1649 | |
| 1650 | /** |
| 1651 | * Set a thread initializer for the given callback. |