ہیلو! آج ہم آپ کو JNDI سے ملوائیں گے۔ آئیے معلوم کریں کہ یہ کیا ہے، اس کی ضرورت کیوں ہے، یہ کیسے کام کرتی ہے، ہم اس کے ساتھ کیسے کام کر سکتے ہیں۔ اور پھر ہم اسپرنگ بوٹ یونٹ ٹیسٹ لکھیں گے، جس کے اندر ہم اسی JNDI کے ساتھ کھیلیں گے۔
تعارف۔ نام اور ڈائریکٹری خدمات
JNDI میں غوطہ لگانے سے پہلے، آئیے سمجھیں کہ نام اور ڈائریکٹری خدمات کیا ہیں۔ ایسی سروس کی سب سے واضح مثال کسی بھی پی سی، لیپ ٹاپ یا اسمارٹ فون پر موجود فائل سسٹم ہے۔ فائل سسٹم فائلوں کا انتظام کرتا ہے (عجیب طور پر کافی)۔ اس طرح کے نظام میں فائلوں کو ایک درخت کی ساخت میں گروپ کیا جاتا ہے. ہر فائل کا ایک منفرد مکمل نام ہوتا ہے، مثال کے طور پر: C:\windows\notepad.exe۔ براہ کرم نوٹ کریں: فائل کا مکمل نام کچھ روٹ پوائنٹ (ڈرائیو C) سے فائل خود (notepad.exe) تک کا راستہ ہے۔ ایسی زنجیر میں انٹرمیڈیٹ نوڈس ڈائریکٹریز (ونڈوز ڈائریکٹری) ہیں۔ ڈائریکٹریز کے اندر موجود فائلوں میں اوصاف ہوتے ہیں۔ مثال کے طور پر، "پوشیدہ"، "صرف پڑھنے کے لیے"، وغیرہ۔ فائل سسٹم جیسی سادہ چیز کی تفصیلی وضاحت نام اور ڈائریکٹری خدمات کی تعریف کو بہتر طور پر سمجھنے میں مدد کرے گی۔ لہذا، ایک نام اور ڈائرکٹری سروس ایک ایسا نظام ہے جو بہت سے ناموں کی نقشہ سازی کو بہت سی اشیاء کے لیے منظم کرتا ہے۔ ہمارے فائل سسٹم میں، ہم فائل کے ناموں کے ساتھ تعامل کرتے ہیں جو اشیاء کو چھپاتے ہیں — فائلیں خود مختلف فارمیٹس میں۔ نام اور ڈائریکٹری سروس میں، نامی اشیاء کو درخت کے ڈھانچے میں منظم کیا جاتا ہے۔ اور ڈائریکٹری آبجیکٹ میں اوصاف ہوتے ہیں۔ نام اور ڈائریکٹری سروس کی ایک اور مثال DNS (ڈومین نیم سسٹم) ہے۔ یہ نظام انسانی پڑھنے کے قابل ڈومین ناموں (مثال کے طور پر، https://javarush.com/) اور مشین کے پڑھنے کے قابل IP پتوں (مثال کے طور پر، 18.196.51.113) کے درمیان نقشہ سازی کا انتظام کرتا ہے۔ DNS اور فائل سسٹم کے علاوہ، بہت سی دوسری خدمات ہیں، جیسے:- لائٹ ویٹ ڈائرکٹری ایکسیس پروٹوکول (LDAP) ؛
- CORBA نام دینے کی خدمت ؛
- نیٹ ورک انفارمیشن سروس (NIS) ؛
- اور دوسرے.
جے این ڈی آئی
JNDI، یا Java Naming and Directory Interface، نام اور ڈائریکٹری خدمات تک رسائی کے لیے Java API ہے۔ JNDI ایک API ہے جو جاوا پروگرام کے لیے مختلف ناموں اور ڈائریکٹری خدمات کے ساتھ تعامل کرنے کے لیے یکساں طریقہ کار فراہم کرتا ہے۔ ہڈ کے تحت، JNDI اور کسی بھی دی گئی سروس کے درمیان انضمام سروس پرووائیڈر انٹرفیس (SPI) کا استعمال کرتے ہوئے مکمل کیا جاتا ہے۔ ایس پی آئی مختلف ناموں اور ڈائریکٹری خدمات کو شفاف طریقے سے منسلک ہونے کی اجازت دیتا ہے، جس سے جاوا ایپلیکیشن JNDI API کو مربوط خدمات تک رسائی حاصل کرنے کی اجازت دیتا ہے۔ ذیل کی تصویر JNDI فن تعمیر کو واضح کرتی ہے:ماخذ: اوریکل جاوا ٹیوٹوریلز
جے این ڈی آئی۔ آسان الفاظ میں معنی
اہم سوال یہ ہے کہ: ہمیں JNDI کی ضرورت کیوں ہے؟ JNDI کی ضرورت ہے تاکہ ہم جاوا کوڈ سے آبجیکٹ کے کچھ "رجسٹریشن" سے جاوا آبجیکٹ حاصل کر سکیں اس آبجیکٹ سے منسلک آبجیکٹ کے نام سے۔ آئیے مذکورہ بالا بیان کو مقالہ میں توڑ دیتے ہیں تاکہ بار بار الفاظ کی کثرت ہمیں الجھن میں نہ ڈالے:- بالآخر ہمیں جاوا آبجیکٹ حاصل کرنے کی ضرورت ہے۔
- ہمیں یہ اعتراض کسی رجسٹری سے ملے گا۔
- اس رجسٹری میں اشیاء کا ایک گروپ ہے۔
- اس رجسٹری میں ہر چیز کا ایک منفرد نام ہے۔
- رجسٹری سے کوئی چیز حاصل کرنے کے لیے، ہمیں اپنی درخواست میں ایک نام پاس کرنا ہوگا۔ گویا یہ کہنا کہ: "براہ کرم مجھے وہ دو جو آپ کے پاس فلاں اور فلاں نام سے ہے۔"
- ہم رجسٹری سے اشیاء کو نہ صرف ان کے نام سے پڑھ سکتے ہیں بلکہ اس رجسٹری میں اشیاء کو مخصوص ناموں سے محفوظ بھی کر سکتے ہیں (کسی نہ کسی طرح وہ وہاں پہنچ جاتے ہیں)۔
JNDI API
JNDI جاوا SE پلیٹ فارم کے اندر فراہم کیا جاتا ہے۔ JNDI استعمال کرنے کے لیے، آپ کو JNDI کلاسز درآمد کرنا ہوں گی، ساتھ ہی ایک یا زیادہ سروس فراہم کنندگان کو نام دینے اور ڈائریکٹری خدمات تک رسائی حاصل کرنے کے لیے ضروری ہے۔ JDK میں درج ذیل خدمات کے لیے خدمات فراہم کرنے والے شامل ہیں:- لائٹ ویٹ ڈائرکٹری ایکسیس پروٹوکول (LDAP)؛
- کامن آبجیکٹ کی درخواست بروکر آرکیٹیکچر (CORBA)؛
- کامن آبجیکٹ سروسز (COS) نام کی خدمت؛
- Java Remote Method Invocation (RMI) رجسٹری؛
- ڈومین نیم سروس (DNS)۔
- javax.naming؛
- javax.naming.directory؛
- javax.naming.ldap؛
- javax.naming.event؛
- javax.naming.spi.
انٹرفیس کا نام
نام کا انٹرفیس آپ کو اجزاء کے ناموں کے ساتھ ساتھ JNDI نام سازی کے نحو کو کنٹرول کرنے کی اجازت دیتا ہے۔ JNDI میں، تمام نام اور ڈائرکٹری کے آپریشنز سیاق و سباق کے مطابق کیے جاتے ہیں۔ کوئی مطلق جڑیں نہیں ہیں۔ لہذا، JNDI ایک InitialContext کی وضاحت کرتا ہے، جو نام دینے اور ڈائریکٹری کے کاموں کے لیے ایک نقطہ آغاز فراہم کرتا ہے۔ ایک بار ابتدائی سیاق و سباق تک رسائی حاصل کرنے کے بعد، اسے اشیاء اور دیگر سیاق و سباق کو تلاش کرنے کے لیے استعمال کیا جا سکتا ہے۔Name objectName = new CompositeName("java:comp/env/jdbc");
مندرجہ بالا کوڈ میں، ہم نے کچھ نام کی وضاحت کی ہے جس کے نیچے کوئی چیز واقع ہے (ہو سکتا ہے یہ واقع نہ ہو، لیکن ہم اس پر اعتماد کر رہے ہیں)۔ ہمارا حتمی مقصد اس چیز کا حوالہ حاصل کرنا اور اسے اپنے پروگرام میں استعمال کرنا ہے۔ لہذا، نام کئی حصوں (یا ٹوکنز) پر مشتمل ہوتا ہے، جسے سلیش سے الگ کیا جاتا ہے۔ ایسے ٹوکن کو سیاق و سباق کہا جاتا ہے۔ سب سے پہلا صرف سیاق و سباق ہے، اس کے بعد کے تمام ذیلی سیاق و سباق ہیں (اس کے بعد ذیلی سیاق و سباق کے طور پر کہا جاتا ہے)۔ سیاق و سباق کو سمجھنا آسان ہے اگر آپ ان کو ڈائریکٹریز یا ڈائریکٹریز، یا صرف باقاعدہ فولڈرز کے مشابہ سمجھتے ہیں۔ روٹ سیاق و سباق روٹ فولڈر ہے۔ ذیلی سیاق و سباق ایک ذیلی فولڈر ہے۔ ہم درج ذیل کوڈ کو چلا کر کسی نام کے تمام اجزاء (سیاق و سباق اور ذیلی سیاق و سباق) دیکھ سکتے ہیں۔
Enumeration<String> elements = objectName.getAll();
while(elements.hasMoreElements()) {
System.out.println(elements.nextElement());
}
آؤٹ پٹ اس طرح ہو گا:
java:comp
env
jdbc
آؤٹ پٹ سے پتہ چلتا ہے کہ نام کے ٹوکن ایک دوسرے سے سلیش کے ذریعے الگ ہو گئے ہیں (تاہم، ہم نے اس کا ذکر کیا ہے)۔ ہر نام کے ٹوکن کا اپنا انڈیکس ہوتا ہے۔ ٹوکن انڈیکسنگ 0 سے شروع ہوتی ہے۔ روٹ سیاق و سباق میں انڈیکس صفر ہے، اگلے سیاق و سباق میں انڈیکس 1 ہے، اگلا 2، وغیرہ۔ ہم ذیلی سیاق و سباق کا نام اس کے اشاریہ سے حاصل کر سکتے ہیں:
System.out.println(objectName.get(1)); // -> env
ہم اضافی ٹوکن بھی شامل کر سکتے ہیں (یا تو آخر میں یا انڈیکس میں کسی مخصوص مقام پر):
objectName.add("sub-context"); // Добавит sub-context в конец
objectName.add(0, "context"); // Добавит context в налачо
طریقوں کی مکمل فہرست سرکاری دستاویزات میں مل سکتی ہے ۔
انٹرفیس سیاق و سباق
اس انٹرفیس میں سیاق و سباق کو شروع کرنے کے لیے مستقل کا ایک سیٹ، نیز سیاق و سباق کو بنانے اور حذف کرنے، اشیاء کو نام سے منسلک کرنے، اور اشیاء کو تلاش کرنے اور بازیافت کرنے کے طریقوں کا ایک مجموعہ شامل ہے۔ آئیے اس انٹرفیس کے استعمال سے انجام پانے والے کچھ آپریشنز کو دیکھتے ہیں۔ سب سے عام عمل نام کے ذریعہ کسی چیز کو تلاش کرنا ہے۔ یہ طریقوں کا استعمال کرتے ہوئے کیا جاتا ہے:Object lookup(String name)
Object lookup(Name name)
bind
:
void bind(Name name, Object obj)
void bind(String name, Object obj)
Object
بائنڈنگ کا الٹا آپریشن - کسی چیز کو نام سے غیر بائنڈنگ، طریقوں کا استعمال کرتے ہوئے کیا جاتا ہے unbind
:
void unbind(Name name)
void unbind(String name)
ابتدائی سیاق و سباق
InitialContext
ایک کلاس ہے جو JNDI درخت کے جڑ عنصر کی نمائندگی کرتی ہے اور لاگو کرتی ہے Context
۔ آپ کو ایک مخصوص نوڈ کے نسبت JNDI درخت کے اندر نام کے ذریعہ اشیاء کو تلاش کرنے کی ضرورت ہے۔ درخت کا جڑ نوڈ اس طرح کے نوڈ کے طور پر کام کر سکتا ہے InitialContext
۔ JNDI کے لیے استعمال کا ایک عام معاملہ ہے:
- حاصل
InitialContext
کریں InitialContext
JNDI درخت سے نام کے ذریعہ اشیاء کو بازیافت کرنے کے لئے استعمال کریں ۔
InitialContext
۔ یہ سب اس ماحول پر منحصر ہے جس میں جاوا پروگرام واقع ہے۔ مثال کے طور پر، اگر جاوا پروگرام اور JNDI ٹری ایک ہی ایپلیکیشن سرور کے اندر چل رہے ہیں، تو یہ InitialContext
حاصل کرنا بہت آسان ہے:
InitialContext context = new InitialContext();
اگر ایسا نہ ہو تو سیاق و سباق حاصل کرنا قدرے مشکل ہو جاتا ہے۔ بعض اوقات سیاق و سباق کو شروع کرنے کے لیے ماحولیاتی خصوصیات کی فہرست پاس کرنا ضروری ہوتا ہے:
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.fscontext.RefFSContextFactory");
Context ctx = new InitialContext(env);
اوپر دی گئی مثال سیاق و سباق کو شروع کرنے کے ممکنہ طریقوں میں سے ایک کو ظاہر کرتی ہے اور اس میں کوئی دوسرا سیمنٹک بوجھ نہیں ہوتا ہے۔ تفصیل سے کوڈ میں غوطہ لگانے کی ضرورت نہیں ہے۔
اسپرنگ بوٹ یونٹ ٹیسٹ کے اندر JNDI استعمال کرنے کی ایک مثال
اوپر، ہم نے کہا کہ JNDI کے نام اور ڈائریکٹری سروس کے ساتھ تعامل کرنے کے لیے، SPI (سروس پرووائیڈر انٹرفیس) کا ہاتھ میں ہونا ضروری ہے، جس کی مدد سے جاوا اور نام دینے کی سروس کے درمیان انضمام کیا جائے گا۔ معیاری JDK کئی مختلف SPIs کے ساتھ آتا ہے (ہم نے انہیں اوپر درج کیا ہے)، جن میں سے ہر ایک مظاہرے کے مقاصد کے لیے بہت کم دلچسپی کا حامل ہے۔ کنٹینر کے اندر JNDI اور Java ایپلیکیشن کو اٹھانا کچھ دلچسپ ہے۔ تاہم، اس مضمون کا مصنف ایک سست شخص ہے، اس لیے یہ ظاہر کرنے کے لیے کہ JNDI کیسے کام کرتا ہے، اس نے کم سے کم مزاحمت کا راستہ منتخب کیا: JNDI کو SpringBoot ایپلیکیشن یونٹ ٹیسٹ کے اندر چلائیں اور Spring Framework سے ایک چھوٹے سے ہیک کا استعمال کرتے ہوئے JNDI سیاق و سباق تک رسائی حاصل کریں۔ تو، ہمارا منصوبہ:- آئیے ایک خالی اسپرنگ بوٹ پروجیکٹ لکھیں۔
- آئیے اس پروجیکٹ کے اندر ایک یونٹ ٹیسٹ بنائیں۔
- ٹیسٹ کے اندر ہم JNDI کے ساتھ کام کرنے کا مظاہرہ کریں گے:
- سیاق و سباق تک رسائی حاصل کریں؛
- JNDI میں کسی نام سے کسی چیز کو باندھنا (بند کرنا)
- آبجیکٹ کو اس کے نام سے حاصل کریں (لوک اپ)؛
- آئیے چیک کریں کہ اعتراض null نہیں ہے۔
- JDBC API؛
- H2 ڈی ڈیٹا بیس۔
SimpleNamingContextBuilder
۔ یہ کلاس آسانی سے JNDI کو یونٹ ٹیسٹوں یا اسٹینڈ اکیلے ایپلی کیشنز کے اندر بڑھانے کے لیے بنائی گئی ہے۔ آئیے سیاق و سباق حاصل کرنے کے لیے کوڈ لکھتے ہیں:
final SimpleNamingContextBuilder simpleNamingContextBuilder
= new SimpleNamingContextBuilder();
simpleNamingContextBuilder.activate();
final InitialContext context = new InitialContext();
کوڈ کی پہلی دو سطریں ہمیں بعد میں آسانی سے JNDI سیاق و سباق کو شروع کرنے کی اجازت دیں گی۔ ان کے بغیر، InitialContext
مثال بناتے وقت ایک استثناء دیا جائے گا: javax.naming.NoInitialContextException
۔ ڈس کلیمر کلاس SimpleNamingContextBuilder
ایک فرسودہ کلاس ہے۔ اور اس مثال کا مقصد یہ بتانا ہے کہ آپ JNDI کے ساتھ کیسے کام کر سکتے ہیں۔ یہ یونٹ ٹیسٹ کے اندر JNDI استعمال کرنے کے بہترین طریقے نہیں ہیں۔ یہ سیاق و سباق کی تعمیر اور JNDI سے اشیاء کو بائنڈنگ اور بازیافت کرنے کا مظاہرہ کرنے کے لئے ایک بیساکھی کہا جا سکتا ہے۔ سیاق و سباق موصول ہونے کے بعد، ہم اس سے اشیاء نکال سکتے ہیں یا سیاق و سباق میں اشیاء کو تلاش کر سکتے ہیں۔ JNDI میں ابھی تک کوئی چیز نہیں ہے، لہذا وہاں کچھ ڈالنا منطقی ہوگا۔ مثال کے طور پر، DriverManagerDataSource
:
context.bind("java:comp/env/jdbc/datasource", new DriverManagerDataSource("jdbc:h2:mem:mydb"));
اس لائن میں، ہم نے کلاس آبجیکٹ کو DriverManagerDataSource
نام سے جوڑ دیا ہے java:comp/env/jdbc/datasource
۔ اگلا، ہم نام سے سیاق و سباق سے آبجیکٹ حاصل کر سکتے ہیں۔ ہمارے پاس اس چیز کو حاصل کرنے کے سوا کوئی چارہ نہیں ہے جسے ہم نے ابھی رکھا ہے، کیونکہ سیاق و سباق میں کوئی دوسری چیزیں نہیں ہیں =(
final DataSource ds = (DataSource) context.lookup("java:comp/env/jdbc/datasource");
اب آئیے چیک کریں کہ ہمارے ڈیٹا سورس کا کنکشن ہے (کنکشن، کنکشن یا کنکشن ایک جاوا کلاس ہے جو ڈیٹا بیس کے ساتھ کام کرنے کے لیے ڈیزائن کیا گیا ہے):
assert ds.getConnection() != null;
System.out.println(ds.getConnection());
اگر ہم نے سب کچھ صحیح طریقے سے کیا تو آؤٹ پٹ کچھ اس طرح ہوگا:
conn1: url=jdbc:h2:mem:mydb user=
یہ کہنا قابل ہے کہ کوڈ کی کچھ لائنیں مستثنیات پھینک سکتی ہیں۔ درج ذیل لائنیں پھینکی جاتی ہیں javax.naming.NamingException
:
simpleNamingContextBuilder.activate()
new InitialContext()
context.bind(...)
context.lookup(...)
DataSource
اسے پھینکا جا سکتا ہے java.sql.SQLException
۔ اس سلسلے میں، یہ ضروری ہے کہ کوڈ کو بلاک کے اندر لاگو کیا جائے try-catch
، یا ٹیسٹ یونٹ کے دستخط میں اس بات کی نشاندہی کریں کہ یہ مستثنیات دے سکتا ہے۔ ٹیسٹ کلاس کا مکمل کوڈ یہ ہے:
@SpringBootTest
class JndiExampleApplicationTests {
@Test
void contextLoads() {
try {
final SimpleNamingContextBuilder simpleNamingContextBuilder
= new SimpleNamingContextBuilder();
simpleNamingContextBuilder.activate();
final InitialContext context = new InitialContext();
context.bind("java:comp/env/jdbc/datasource", new DriverManagerDataSource("jdbc:h2:mem:mydb"));
final DataSource ds = (DataSource) context.lookup("java:comp/env/jdbc/datasource");
assert ds.getConnection() != null;
System.out.println(ds.getConnection());
} catch (SQLException | NamingException e) {
e.printStackTrace();
}
}
}
ٹیسٹ چلانے کے بعد، آپ درج ذیل لاگز دیکھ سکتے ہیں:
o.s.m.jndi.SimpleNamingContextBuilder : Activating simple JNDI environment
o.s.mock.jndi.SimpleNamingContext : Static JNDI binding: [java:comp/env/jdbc/datasource] = [org.springframework.jdbc.datasource.DriverManagerDataSource@4925f4f5]
conn1: url=jdbc:h2:mem:mydb user=
GO TO FULL VERSION