Тема: Java Tip 20: Write a custom security manager that gathers execution in
You can trace the origin of a method call using a custom SecurityManager class
By Mark Wutka, JavaWorld.com, 11/01/96
http://www.javaworld.com/javatips/jw-javatip20.html
Зневаджуючи Java програму інколи виникає бажання встановити зв'язок між методом і класом, який його викликав. Це бажання виникає майже одразу, коли починаєш писати клас. Складність полягає у тому, що одним із принципів ООП засвідчено: "Об'єкт не залежить від того, що його викликало". Тим не менш, якщо ви шукаєте непрацюючі методи у великій програмі, то додавання деякого зневаджуючого коду, який вказував би на непрацюючий об'єкт буде дуже доцільно.
Клас SecurityManager має один зручний метод, який повертає контекст класу поточного виклику методу. Іншими словами, він надасть нам масив об'єктів Класу, який представлятиме класи, задіяні для того, щоб викликати даний метод. Розглянемо випадок, коли "Foo" викликаний методом, який міститься в "Bar", а "Bar" в свою чергу викликається методом із "Baz"; контекст класу поточного виклику методу в "Baz" буде містити "Baz", "Bar" та "Foo", в приведеному порядку. Останній застосований клас завжди буде першим в списку. Назва цього методу - getClassContext.
На жаль, використання getClassContext має одну незручність - це захищений метод. Однак, ви можете порушити іще один принцип ООП і надати доступ до захищеного методу через субклас. Класс DummySM, приведений далі, продемонструє як це зробити:
public class DummySM extends SecurityManager
{ public Class[] context()
{ return getClassContext(); }
}
Для того, щоб "дати зрозуміти" методу, які класи його викликали, можна використати конткстний метод. Об'єкт ShowCaller виводить весь контекст класу для методу callme. В першу чергу він здійснює перевірку, щоб побачити чи DummySM використовується в якості SecurityManager-класу.
public class ShowCaller extends Object
{ public ShowCaller() { }
public void callme() {
// Get the current security manager SecurityManager sm =
System.getSecurityManager();
// Make sure the security manager is a DummySM
if (sm instanceof DummySM) {
DummySM dummy = (DummySM) sm;
// Get the class context
Class classes[] = dummy.context();
// Print the context
System.out.println("Callme context:");
for (int i=0; i < classes.length; i++) {
System.out.println(classes[i]);
}
}
}
}
Те, що приведено нижче - це пара dummy (фіктивних) класів. Їх ми використовуємо для тестування ShowCaller.java. Об'єкти, які надані ShowCaller-об'єкту, викликають callme метод в ShowCaller.
public class FooCaller extends Object
{ ShowCaller caller;
public FooCaller(ShowCaller caller)
{ this.caller = caller; }
public void callme()
{ caller.callme(); }
}
public class BarCaller extends Object
{ ShowCaller caller;
public BarCaller(ShowCaller caller)
{ this.caller = caller; }
public void callme()
{ caller.callme(); }
}
І, насамкінець, програма, яка продемонструє це:
public class TestContext extends Object
{ public static void main(String[] args) {
// Set DummySM as the security manager for this program
System.setSecurityManager(new DummySM());
ShowCaller sc = new ShowCaller();
FooCaller foo = new FooCaller(sc);
BarCaller bar = new BarCaller(sc);
foo.callme();
bar.callme(); }
}
Якщо ви будете використовувати цей механізм, як частину конструкції реального класу, вам доведеться сильно змінювати його дизайн. За нормальних умов, об'єкт не має знати що саме його викликало.
Про автора
Mark Wutka є автором майбутньої книги Hacking Java: The Java Professional's Resource Kit (ISBN: 0-7897-0935-X), а також являється укладачем перших двох видань Que's SE Using Java.