Cho phép cài plugin trong java như thế nào?
Chả là đang tập tọe làm wordpress plugin, bỗng dưng nảy ra câu hỏi thế cài đặt plugin trong java như thế nào. Trước giờ cũng chỉ làm theo kiểu yêu cầu đến đâu viết đến đấy chứ chưa được làm kiểu plugin này bao giờ cả. Đành hỏi bác Gúc vậy. Sau một hồi đào bới cũng gọi là nắm đưọc đôi ...
Chả là đang tập tọe làm wordpress plugin, bỗng dưng nảy ra câu hỏi thế cài đặt plugin trong java như thế nào. Trước giờ cũng chỉ làm theo kiểu yêu cầu đến đâu viết đến đấy chứ chưa được làm kiểu plugin này bao giờ cả. Đành hỏi bác Gúc vậy. Sau một hồi đào bới cũng gọi là nắm đưọc đôi phần, note ra đây cho bác nào cùng chung thắc mắc.
Plugin là khỉ gì?
Nói thế chứ plugin chắc không lạ gì rồi, điển hình như các thể loại trình duyệt phổ biến như Chrome, Firefox, Opera kiểu gì mỗi cái chả cài một đống plugin đến khi trình duyệt có gì bất thường lại chả lôi đầu mấy thằng plugin ra kiểm ra đầu tiên. Một cách đơn giản thì Plugin chính là một bộ phần mềm cài đặt để hỗ trợ, mở rộng chức năng cho một phần mềm ứng dụng lớn hơn, dựa trận nhưng giao thức và API do phần mềm lớn cung cấp.
Plugin có gì hay ho?
Kiến trúc plugin thực sự rất tuyệt vời, nó cho phép mở rộng (thập chí là thay đổi) các chức năng của các host applications (tạm gọi là ứng dụng chủ đi), với một thiết kế tốt các ứng dụng có thể cắm thêm bao nhiêu chức năng tùy thích mỗi plugin mang đến một tiện ích dẫn đến khả năng mở rộng của hệ thống là cực kỳ tuyệt vời mình xin phép đưọc nhai lại một lần nữa là phải thiết kế cho tốt nhé không là ứng úng lỗi tùm lum đó.
Với cộng đồng mã nguồn mở phát triển như vũ bão ngày nay, với một ứng dụng có base tốt và một plugin API tối thì tốc độ phát triển sẽ không thể tin nổi. VD như slack một hệ thống nhắn tin và trao đổi công việc đang rất nổi tuy cũng chỉ mới phát triển được vài năm nhưng số lượng plugin trong kho của slack đã rất khổng lồ hầu hết là do các bên thứ ba phảt triển, thực sự nâng giá trị của ứng dụng ban đầu lên gấp nhiều lần mà một team không thể làm hết được.
Rồi, thế cài đặt thằng này thế nào?
Đối với các script language như Javascript, PHP, python… với dặc điểm mỗi lần chạy là một lầnthông dịch thì có vẻ không gặp trở ngại gì chỉ việc dùng một thằng callback là xong cái này mình sẽ nói đến vào một ngày đẹp trời không xa. Với Java câu chuyện có vẻ không dễ dàng như thế, Java thì khônng có callback hay cái gì tượng tự cả, mình thì gà Java nên cũng thấy vụ này hơi khoai một chút.
Về cơ bản để có thể cắm được plugin thì ứng dụng phải có kiến trúc đơn giản nhất như trong hình trên, hai thành phần cơ bản đó là application core và plugin manager:
– application core: thằng này là ứng dụng chủ có nhiệm bụ bào đảm logic của hệ thống, thực hiện các tác vụ và hook (gọi) các plugin thực hiện nhiệm vụ của mình trong runtime.
– plugins manager: thằng chịu sự chỉ đạo của thằng core có nhiệm vụ đăng ký các plugin thêm, gỡ, bật, tắt các plugin.
Để có thể cắm được plugin ta phải có một plugin interface đây là giao diện mà tất cả các plugin sẽ kế thừa, plugin manager sẻ load các plugins và initial (nôm na là tạo ra thực thể của mỗi plugin) vào trong một List các plugins rồi từ đó application core sẽ lần lưọt móc ra từ cái một và bắt nó thực hiện nhiệm vụ nhất định.
Hì, mình giải thích củ chuối quá chắc ko ai hiểu nổi nhỉ. Để trực quan sinh động mời ae xem ví dụ bên dưới.
Ví dụ trực quan nè
ở ví dụ này mình sẽ tạo một ứng dụng đơn giẩn với đầu vào là 1 số, các plugin sẽ đưọc thêm vào đê chế biến số đó để đưa ra kết quả cuối cùng cộng trừ nhân chia gì đó.
Ok, đầu tiên chúng ta phải có một thằng interface chung cho các plugins. tạm gọi làPluginFunction.java đi.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public interface PluginFunction { // let the application pass in a parameter public void setParameter (int param); // retrieve a result from the plugin public int getResult(); // return the name of this plugin public String getPluginName(); // can be called to determine whether the plugin // aborted execution due to an error condition public boolean hasError(); } |
Tiếp theo ta phải có một cái main để chạy logic của ứng dụng và gọi các plugin, ta gọi làPluginDemo.java chứa hàm main.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
import java.io.File; import java.util.*; public class PluginDemo { //parameter for plugins int count; // the directory where we keep the plugin classes String pluginsDir; // a list where we keep an initialized object of each plugin class List plugins; public static void main (String args[]) { PluginDemo demo = new PluginDemo(args); demo.getPlugins(); demo.runPlugins(); } PluginDemo (String args[]) { if (args.length > 0) count = Integer.parseInt(args[0]); else count = 1; if (args.length > 1) pluginsDir = args[0]; else pluginsDir = "plugins"; plugins = new ArrayList(); System.setSecurityManager(new PluginSecurityManager(pluginsDir)); } protected void getPlugins() { File dir = new File(System.getProperty("user.dir") + File.separator + pluginsDir); ClassLoader cl = new PluginClassLoader(dir); if (dir.exists() && dir.isDirectory()) { // we'll only load classes directly in this directory - // no subdirectories, and no classes in packages are recognized String[] files = dir.list(); for (int i=0; i<files.length; i++) { try { // only consider files ending in ".class" if (! files[i].endsWith(".class")) continue; Class c = cl.loadClass(files[i].substring(0, files[i].indexOf("."))); Class[] intf = c.getInterfaces(); for (int j=0; j<intf.length; j++) { if (intf[j].getName().equals("PluginFunction")) { // the following line assumes that PluginFunction has a no-argument constructor PluginFunction pf = (PluginFunction) c.newInstance(); plugins.add(pf); continue; } } } catch (Exception ex) { System.err.println("File " + files[i] + " does not contain a valid PluginFunction class."); } } } } protected void runPlugins() { Iterator iter = plugins.iterator(); while (iter.hasNext()) { PluginFunction pf = (PluginFunction) iter.next(); try { pf.setParameter(count); System.out.print(pf.getPluginName()); System.out.print(" ( "+count+" ) = "); if (pf.hasError()) { System.out.println("there was an error during plugin initialization"); continue; } int result = pf.getResult(); if (pf.hasError()) System.out.println("there was an error during plugin execution"); else System.out.println(result); count++; } catch (SecurityException secEx) { System.err.println("plugin '"+pf.getClass().getName()+"' tried to do something illegal"); } } } } |
Ta thấy trong hàm getPlugins có một vòng for để load hết các class mà có interface làPluginFunction rồi tạo ra một thực thể của class đó và lưu vào mảng plugins. Sau đó hàmrunPlugins sẽ duyệt qua tất cả cảc plugins set tham số chạy hàm run của từng plugin và in ra kết quả.
Ngoài ra hàm getPlugins còn có một điều thú vị nữa chính là dòng setSecurityManager, vì đây là các plugins độc lập với hệ thống nên ta phải xét quền hạn cho nó chứ nhỡ thanh niên nào vui tính lại cho cái plugin xóa hết hệ điều hành thì chỉ biết ngồi đấy mà khóc thôi .
Đây là nội dung file PluginSecurityManager.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
import java.io.File; /** * This is a fairly uptight security manager subclass. Classes loaded by * the PluginClassLoader are highly restricted in what they are allowed to do. * This is okay, because they're only supposed to calculate some values, * for which all necessary data is already available to them. * * A SecurityManager consists of various methods that the system calls to * check whether certain sensitive operations should be allowed. These * methods can throw a SecurityException to prevent the operation from * happening. With this SecurityManager, we want to prevent untrusted * code that was loaded by a class loader from performing those sensitive operations. * So we use inherited SecurityManager methods to check whether the call is being * made by an untrusted class. If it is, we throw an exception. * Otherwise, we simply return, allowing the operation to proceed normally. */ public class PluginSecurityManager extends SecurityManager { private String pluginDir = null; PluginSecurityManager (String dir) { pluginDir = dir; } /** * This is the basic method that tests whether there is a class loaded * by a ClassLoader anywhere on the stack. If so, it means that that * untrusted code is trying to perform some kind of sensitive operation. * We prevent it from performing that operation by throwing an exception. * trusted() is called by most of the check...() methods below. */ protected void trusted() { if (inClassLoader()) throw new SecurityException(); } /** * These are all the specific checks that a security manager can * perform. They all just call one of the methods above and throw a * SecurityException if the operation is not allowed. This * SecurityManager subclass is perhaps a little too restrictive. For * example, it doesn't allow loaded code to read *any* system properties, * even though some of them are quite harmless. */ public void checkCreateClassLoader() { trusted(); } public void checkAccess (Thread g) { trusted(); } public void checkAccess (ThreadGroup g) { trusted(); } public void checkExit (int status)
Có thể bạn quan tâm
0
|