Monday, November 20, 2006

پشتیبانی جاوا از زبان های اسکریپتی (2)

در پست قبلی در مورد قابلیت تعامل جاوا با زبان های اسکریپتی در JDK 6 و قدرت بالای این ویژگی گفتم. در این پست برای اینکه موضوع بیشتر مشخص شود یک مثال کاربردی آورده ام. احتمالا در پست بعدی مثال دیگری را خواهم آورد.

قابلیت گسترش

امروزه برنامه هایی که می شود به آنها plug-in اضافه کرد یا آنها را به نحوی customize کرد خیلی متداول شده. خیلی خوب است اگر کاربر بتواند برنامه ای را که در دست دارد به نحوی آنطور که می خواهد تغییر دهد یا چیزی به آن اضافه کند. اضافه کردن چنین ویژگی هایی به یک برنامه در جاوا دو راه حل کلی(حداقل تا آنجا که من می دانم) دارد. یک راه حل مشکل و یک راه حل ساده. راه حل مشکل همان راه حلی است که eclipse و بسیاری دیگر از IDE ها و برنامه های تجاری از آن استفاده می کنند و آن هم اضافه کردن این قابلیت با استفاده از تعریف یک سری extension point است. توسعه دهندگان می توانند با استفاده از پروتکلی که برنامه اصلی تعریف می کند extension های خود را به برنامه اضافه کنند(این پروتکل معمولا بصورت یک DTD یا یک چیزی شبیه به آن به علاوه یک سری interface جاوا هست). برنامه اصلی معمولا از Java Reflection برای اضافه کردن extension ها به خود استفاده می کند.

ولی راه حل ساده استفاده از یک زبان اسکریپتی به همراه جاوا هست(همان کاری که jEdit انجام می دهد). در این راه حل قسمت عمده برنامه با استفاده از جاوا نوشته و کامپایل می شود و قسمت کوچکی از برنامه می تواند (بعدا) توسط یک زبان اسکریپتی نوشته و به برنامه اضافه شود. هر کدام از این روش ها مزایا و معایب خاص خود را دارد ولی در اینجا نمی خواهم به آنها بپردازم. کدی که در ادامه آورده شده یک مثال بسیار ساده(ولی کامل) از این روش است.

package com.blogspot.zoftware.jdk6.script;

import java.awt.BorderLayout;

import java.io.File;

import java.io.FileReader;

import javax.script.ScriptEngine;

import javax.script.ScriptEngineManager;

import javax.swing.JButton;

import javax.swing.JFrame;

public class ScriptedUI extends JFrame {

private JButton button = new JButton("Click Here");

public ScriptedUI() {

super("Script Demo");

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

setLayout(new BorderLayout());

add(button);

setSize(180, 70);

}

public JButton getButton() {

return button;

}

static void runScripts(ScriptEngine eng, String folder) {

File[] scripts = new File(folder).listFiles();

for (File script : scripts) {

if (script.getName().endsWith(".js")) {

try {

eng.eval(new FileReader(script));

} catch (Exception e) {

e.printStackTrace();

}

}

}

}

public static void main(String[] args) {

ScriptEngineManager factory = new ScriptEngineManager();

ScriptEngine bootstrapEng = factory.getEngineByName("JavaScript");

runScripts(bootstrapEng, "scripts/bootstrap");

ScriptedUI frame = new ScriptedUI();

ScriptEngine startupEng = factory.getEngineByName("JavaScript");

startupEng.put("frame", frame);

runScripts(startupEng, "scripts/startup");

frame.setVisible(true);

}

}

این برنامه هنگام شروع ابتدا هر اسکریپتی را که در پوشه scripts/bootstrap و با پسوند js وجود داشته باشد می خواند و اجرا می کند. سپس یک فریم می سازد و بعد از آن اسکریپت های پوشه scripts/startup را اجرا می کند. در اسکریپت های پوشه scripts/startup متغیر frame تعریف شده هست.

http://photos1.blogger.com/blogger/1266/3268/320/scripts.0.png

اگر در پوشه های starup و bootstrap فایلی وجود نداشته باشد، فریم نشان داده شده با LookAndFeel پیش فرض جاوا (Metal) و با اندازه مشخص شده در برنامه نشان داده می شود. حالا فرض کنیم بخواهیم LookAndFeel را تغییر دهیم. کافی است در پوشه scripts/bootstrap یک فایل با پسوند js قرار داده و داخل آن کد جاوا اسکریپت زیر را بنویسیم.

/* folder: scripts/bootstrap */
importPackage(javax.swing);
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

با اضافه کردن این فایل و اجرای مجدد برنامه شکل فریم تغییر می کند(شکل 2) و LookAndFeel برنامه همانند بقیه برنامه های سیستم می شود. اگر به کد برنامه دقت کرده باشید در خط 48 متغیر frame به موتور اسکریپت پاس می شود(به این معنی که این متغیر درون اسکریپت های پوشه startup شناخته شده است). حال اگر یک فایل با محتویات زیر درون پوشه scripts/startup قرار دهیم شکل فریم تغییر کرده و به شکل 3 در می آید. همچنین این فایل یک ActionListener به Button اضافه می کند که هنگام کلیک بر روی آن یک MessageBox به نمایش در می آید(شکل 4).

/* folder: scripts/startup */

frame.button.text = 'Do Not Click Please';

frame.setSize(200, 70);

importPackage(javax.swing);

listener = function(e){ JOptionPane.showMessageDialog(frame,

"You Clicked on " + e.source.text); }

frame.button.addActionListener(listener);

توجه دارید که بدون استفاده از زبان اسکریپتی، برای گسترش برنامه باید سورس آن را تغییر دهیم و دوباره آنرا کامپایل کنیم ولی با استفاده از این روش نیازی به کامپایلر نداریم. با استفاده از این روش، کاربر به آسانی می تواند محیط گرافیکی برنامه را تغییر داده و کامپوننت ها و منو های جدید به آن اضافه کند. البته این روش فقط خاص محیط گرافیکی نیست و می توان در بسیاری از موارد دیگر مانند نوشتن فایل های Configuratin برای برنامه نیز از آن استفاده کرد.

مثالی که در اینجا آورده شد بدون هیچ تغییر و نیاز به کتابخانه اضافی در JDK 6 اجرا می شود ولی اگر لازم باشد در ویرایش های قدیمی تر JDK اجرا شود نیاز به کمی تغییر و اضافه کردن کتابخانه های مورد نیاز است.

نکته آخر اینکه همیشه لازم نیست که extension ها کاملا به زبان اسکریپتی نوشته شود و می توان خود extension را با جاوا نوشت و کامپایل کرد و از زبان اسکریپتی بصورت یک چسپ برای اتصال extension ها استفاده کرد.

No comments: