Именование и операции с каталогами
ты можешь использовать этоJNDIВыполните следующие операции: операции чтения и операции обновления пространства имен. В этом разделе описываются эти две операции:
l объект запроса
l Список контекстного контента
l Добавлять, переопределять и удалять привязки
l переименовать объект
l Создание и удаление дочерних контекстов
настроить
Перед выполнением операций в службах именования и каталогов необходимо получить контекст инициализации — начальную точку пространства имен. Потому что все методы именования и службы каталогов выполняются относительно некоторого контекста.
Чтобы получить контекст инициализации, необходимо выполнить следующие шаги:
1. Выберите провайдера доступа, к которому вы хотите получить доступ.
2. Указывает желаемый контекст инициализации.
3. перечислитьInitialContextКонструктор.
Шаг 1. Выберите поставщика услуг для контекста инициализации.
Вы можете указать поставщика услуг для контекста инициализации, создав набор переменных среды (Hashtable), включая имя поставщика услуг. свойства окружающей среды вJNDIПодробности есть в учебнике.
если вы используетеSunизLDAPПоставщик услуг, код выглядит следующим образом:
Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory"); |
указатьSunПоставщик службы файловой системы для , код выглядит следующим образом:
Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.fscontext.RefFSContextFactory"); |
Вы можете использовать некоторые системные свойства для описания используемого поставщика услуг. существуетJNDIОн подробно описан в учебнике.
Шаг 2. Предоставьте информацию, необходимую для инициализации контекста.
Клиентам разных каталогов может потребоваться предоставить различную информацию для подключения к каталогу. Например, вам нужно указать машину, на которой работает сервер, и идентифицировать пользователя в каталоге. Эта информация передается поставщику услуг через свойства среды.JNDIУказывает общие параметры среды, используемые поставщиком услуг. Документация поставщика услуг содержит подробное описание параметров, которые необходимо предоставить.
LDAPПровайдеру нужна программа для предоставленияLDAPРасположение сервера и информация для аутентификации. Для предоставления этой информации требуется следующий код:
env.put(Context.PROVIDER_URL, "ldap://ldap.wiz.com:389"); env.put(Context.SECURITY_PRINCIPAL, "joeuser"); env.put(Context.SECURITY_CREDENTIALS, "joepassword"); |
используется в этом урокеSunизLDAPпоставщики услуг. В примере предполагается, что сервер установлен на локальной машине, используйте389порт, корневое отличительное имя "o=JNDITutorial", для изменения каталога аутентификация не требуется. Эта информация необходима для настройки среды.
env.put(Context.PROVIDER_URL, "ldap://localhost:389/o=JNDITutorial"); |
Если вы используете каталог с другими настройками, вам необходимо установить соответствующее свойство среды. Вам нужно заменить " на имя машиныlocalhost". Вы можете запускать примеры на любом общедоступном сервере каталогов или на своем собственном сервере на другой машине. Вам нужно добавить "localhost” с названием этой машины, иo=JNDITutorialЗамените соответствующим контекстом именования.
Шаг 3: Создайте контекст инициализации
Вы создали контекст инициализации. Для этого вы помещаете созданное ранее свойство среды вInitialContextВ конструкторе:
Context ctx = new InitialContext(env); |
Теперь, когда у вас есть ссылка на объект контекста, вы можете начать доступ к службе имен.
Для выполнения операций с каталогами вам необходимо использоватьInitialDirContext. Для этого используйте один из его конструкторов:
DirContext ctx = new InitialDirContext(env); |
Этот оператор возвращает значение, используемое для операций с каталогами.DirContextссылка на объект.
Исключение именования
JNDIМногие методы в пакете генерируют исключения, указывающие на то, что запрос операции не может быть выполнен. В общем, вы увидите, что вы можете броситьNamingExceptionметод с использованиемtry/catchупаковать.
try { Context ctx = new InitialContext(); Object obj = ctx.lookup("somename"); } catch (NamingException e) { // Handle the error System.err.println(e); } |
структура класса исключений
JNDIСуществует богатая структура исключений, все исключения являются производными отNamingExceptionНаследование в классе. Имена классов исключений говорят сами за себя и перечислены ниже.
Если вы хотите иметь дело с конкретнымNamingExceptionподклассы, которые должны быть отдельноcatchПодкласс. Например, следующий код специально обрабатываетAuthenticationExceptionи его подклассы.
try { Context ctx = new InitialContext(); Object obj = ctx.lookup("somename"); } catch (AuthenticationException e) { // attempt to reacquire the authentication information ... } catch (NamingException e) { // Handle the error System.err.println(e); } |
перечислить
Такие какContext.list()иDirContext.search()Эта операция возвращаетNamingEnumeration. В этих случаях, если возникает ошибка и результаты не возвращаются,NamingExceptionили его подклассы будут выброшены по запросу метода. Если произошла ошибка и был возвращен частичный результат, вернитеNamingEnumerationТаким образом, вы можете достичь этих результатов. После получения всех результатов запроситеNamingEnumeration.hasMore()приведет к броскуNamingException(или его подклассы), указывающее, что произошла ошибка. В этом случае перечисление становится недопустимым и ни один из его методов больше не может быть запрошен.
Например, если вы выполнитеsearch()и укажите, сколько результатов нужно вернуть, затемsearch()вернуться самое большееnрезультат. Если результат превышаетnодин, то когда первыйn+1ЗапросыNamingEnumeration.hasMore()при броскеSizeLimitExceededException. Смотрите в этом разделе оlimitпример кода.
Примеры в этом руководстве
В онлайн-примере кода в этом файле руководства обычно опускается для удобства чтения.try/catchутверждение. Обычно, поскольку здесь показана только часть фрагмента кода, показаны только те строки, которые непосредственно представляют концепцию. Если вы посмотрите на исходные файлы, сопровождающие это руководство, вы увидитеtry/catchподходящее место для заявления.
javax.namingИсключение в пакете можно увидеть здесь.
объект запроса
Чтобы запросить объекты из службы имен, используйтеContext.lookup()метод и передать имя объекта, который вы хотите получить. Предположим, что в службе имен есть объект, имя которогоcn=Rosanna Lee,ou=People. Чтобы получить этот объект, вам просто нужно написать:
Object obj = ctx.lookup("cn=Rosanna Lee,ou=People"); |
lookup()Тип возвращаемого объекта зависит от службы именования и данных, связанных с объектом. Служба имен может содержать множество различных типов объектов, и объекты, запрашиваемые в разных частях системы, могут одновременно получать разные типы. Например,"cn=Rosanna Lee,ou=People" привязан к объекту контекста (javax.naming.ldap.LdapContext). ты сможешьlookup()результат методаcastв нужный класс.
Например, следующий код запрашивает "cn=Rosanna Lee,ou=People«Объект иcastстатьLdapContext.
import javax.naming.ldap.LdapContext; ... LdapContext ctx = (LdapContext) ctx.lookup("cn=Rosanna Lee,ou=People"); |
Полный пример находится наLookup.javaв файле.
существуетJava SE 6В QueryName представлены два новых статических метода:
l InitialContext.doLookup(Name name)
l InitialContext.doLookup(String name)
Эти методы не предоставляют экземплярInitialContextЯрлыки для поиска объектов.
перечислить контекст
заменятьContext.lookup()методов, которые получают один объект за раз, вы можете перечислить весь остальной текст за одну операцию. Существует два способа перечисления контекста: один возвращает отношение привязки, другой просто возвращает имя-Название типа объекта.
Context.List()метод
Context.list()возвращениеNameClassPairперечисление . каждыйNameClassPairСодержит имя объекта и имя типа объекта. В следующем коде перечислены "ou=People"Содержимое каталога (например, "ou=People” для поиска файлов и каталогов).
NamingEnumeration list = ctx.list("ou=People");
while (list.hasMore()) { NameClassPair nc = (NameClassPair)list.next(); System.out.println(nc); } |
Возвращаемое значение выглядит следующим образом:
# java List cn=Jon Ruiz: javax.naming.directory.DirContext cn=Scott Seligman: javax.naming.directory.DirContext cn=Samuel Clemens: javax.naming.directory.DirContext cn=Rosanna Lee: javax.naming.directory.DirContext cn=Maxine Erlund: javax.naming.directory.DirContext cn=Niels Bohr: javax.naming.directory.DirContext cn=Uri Geller: javax.naming.directory.DirContext cn=Colleen Sullivan: javax.naming.directory.DirContext cn=Vinnie Ryan: javax.naming.directory.DirContext cn=Rod Serling: javax.naming.directory.DirContext cn=Jonathan Wood: javax.naming.directory.DirContext cn=Aravindan Ranganathan: javax.naming.directory.DirContext cn=Ian Anderson: javax.naming.directory.DirContext cn=Lao Tzu: javax.naming.directory.DirContext cn=Don Knuth: javax.naming.directory.DirContext cn=Roger Waters: javax.naming.directory.DirContext cn=Ben Dubin: javax.naming.directory.DirContext cn=Spuds Mackenzie: javax.naming.directory.DirContext cn=John Fowler: javax.naming.directory.DirContext cn=Londo Mollari: javax.naming.directory.DirContext cn=Ted Geisel: javax.naming.directory.DirContext |
Context.listBindings()метод
Context.listBindings()Метод возвращает связанное перечисление. привязкаNameClassPairподкласс . Привязки содержат не только имена объектов и имена классов объектов, но и сами объекты. Следующий фрагмент кода перечисляет "ou=People», распечатывая каждое имя привязки и объект.
NamingEnumeration bindings = ctx.listBindings("ou=People");
while (bindings.hasMore()) { Binding bd = (Binding)bindings.next(); System.out.println(bd.getName() + ": " + bd.getObject()); } |
Возвращаемые результаты следующие:
# java ListBindings cn=Jon Ruiz: com.sun.jndi.ldap.LdapCtx@1d4c61c cn=Scott Seligman: com.sun.jndi.ldap.LdapCtx@1a626f cn=Samuel Clemens: com.sun.jndi.ldap.LdapCtx@34a1fc cn=Rosanna Lee: com.sun.jndi.ldap.LdapCtx@176c74b cn=Maxine Erlund: com.sun.jndi.ldap.LdapCtx@11b9fb1 cn=Niels Bohr: com.sun.jndi.ldap.LdapCtx@913fe2 cn=Uri Geller: com.sun.jndi.ldap.LdapCtx@12558d6 cn=Colleen Sullivan: com.sun.jndi.ldap.LdapCtx@eb7859 cn=Vinnie Ryan: com.sun.jndi.ldap.LdapCtx@12a54f9 cn=Rod Serling: com.sun.jndi.ldap.LdapCtx@30e280 cn=Jonathan Wood: com.sun.jndi.ldap.LdapCtx@16672d6 cn=Aravindan Ranganathan: com.sun.jndi.ldap.LdapCtx@fd54d6 cn=Ian Anderson: com.sun.jndi.ldap.LdapCtx@1415de6 cn=Lao Tzu: com.sun.jndi.ldap.LdapCtx@7bd9f2 cn=Don Knuth: com.sun.jndi.ldap.LdapCtx@121cc40 cn=Roger Waters: com.sun.jndi.ldap.LdapCtx@443226 cn=Ben Dubin: com.sun.jndi.ldap.LdapCtx@1386000 cn=Spuds Mackenzie: com.sun.jndi.ldap.LdapCtx@26d4f1 cn=John Fowler: com.sun.jndi.ldap.LdapCtx@1662dc8 cn=Londo Mollari: com.sun.jndi.ldap.LdapCtx@147c5fc cn=Ted Geisel: com.sun.jndi.ldap.LdapCtx@3eca90 |
ЗаканчиватьNamingEnumeration
NamingEnumerationПрекращение может быть выполнено тремя способами: общим, явным, неявным.
l когдаNamingEnumeration.hasMore()возвращениеfalse, перечисление заканчивается и завершается.
l Вы можете запросить до окончания перечисленияNamingEnumeration.close()Метод явно завершает перечисление. Это побуждает базовую реализацию освободить все ресурсы, связанные с перечислением.
l еслиhasMore()илиnext()Метод генерирует любое исключение, и перечисление немедленно завершается.
Независимо от того, как завершается перечисление, после завершения перечисления его нельзя использовать. Запрос любого метода в завершенном перечислении приводит к неопределенным результатам.
Зачем использовать два разных метода?
list()Подготовлено для приложений типа просмотра, возвращает только имя объекта в контексте. Например, браузер может отображать имена в контексте, ожидая, что пользователь выберет одно или несколько отображаемых имен для последующего действия. Этим приложениям обычно не требуется доступ ко всем объектам в контексте.
listBindings()Подготовлено для приложений, которым необходимо работать с объектами контекста. Например, программа резервного копирования должна выполнить "file stats". Кроме того, программа администратора принтера может захотеть перезапустить все принтеры в здании. Для выполнения этих операций необходимо получить все объекты в контексте. Поэтому возврат объектов как части перечисления является временной мерой.
Приложения могут выбирать в зависимости от типа необходимой информацииlist()илиlistBindings().
Добавить, заменить или удалить привязки
ContextИнтерфейс содержит методы для добавления, замены и удаления привязок в контексте.
добавить привязку
Context.bind()Чтобы добавить привязку к контексту, он принимает в качестве параметров тип объекта и объект, который необходимо привязать.
прежде чем продолжить: примеры в этом руководстве требуют внесения дополнительных изменений в схему. ты должен закрытьLDAPОбнаружение схемы сервера или добавление схемы, соответствующей этому руководству, на сервер. Обычно эту работу выполняют администраторы сервера каталогов. Пожалуйста, посмотрите курс.
// Create the object to be bound Fruit fruit = new Fruit("orange");
// Perform the bind ctx.bind("cn=Favorite Fruit", fruit); |
Этот пример создаетFruitОбъекты класса также находятся в контекстеctxпривязать его к имени"cn=Favorite FruitЕсли вы тогдаctxЗапрос в "cn=Favorite Fruit", то вы получитеfruitденежные средства. Обратите внимание, что компиляцияFruitпотребности классаFruitFactoryсвоего рода.
Если вы запустите этот пример дважды, второй раз вызоветNameAlreadyBoundExceptionИсключение не выполнено. так как"cn=Favorite Fruit” уже привязан. Чтобы запустить второй раз без сбоев, нужно использоватьrebind().
Добавить или изменить привязки
rebind()Используется для добавления или замены привязок. его список параметров иbind()то же самое, но если имя уже привязано, то сначалаunboundЗатем повторно привяжите новый объект.
// Create the object to be bound Fruit fruit = new Fruit("lemon");
// Perform the bind ctx.rebind("cn=Favorite Fruit", fruit); |
Когда вы запустите этот пример, он заменитbind()Отношение привязки, созданное в примере.
удалить привязку
Чтобы удалить привязку, используйтеunbind().
// Remove the binding ctx.unbind("cn=Favorite Fruit"); |
Когда этот пример запустится, удалитеbind()илиunbind()Создал привязки.
Переименовать
ты используешьContext.rename()Переименовывать объекты в контексте.
// Rename to Scott S ctx.rename("cn=Scott Seligman", "cn=Scott S"); |
Этот пример будет привязан к "cn=Scott Seligman"Объект привязан к"cn=Scott S". После переименования объекта проверки программа переименовывает его обратно в исходное имя ("cn=Scott Seligman"),Следующее:
// Rename back to Scott Seligman ctx.rename("cn=Scott S", "cn=Scott Seligman"); |
больше оLDAPПожалуйста, обратитесь к примеру переименования вLDAPпродвинутое внимание.
Создание и удаление дочерних контекстов
ContextИнтерфейс состоит из создания и уничтожения подконтекста. Подконтексты — это контексты, которые связаны с другими контекстами.
В этом примере используется объект со свойствами, а затем создаются подконтексты в каталоге. ты можешь использовать этоDirContextМетод связывает свойства и объекты при добавлении привязки или подконтекста в пространство имен. Например, вы можете создатьPersonобъект, а затемPersonОбъект связан со свойствами и привязывает его к пространству имен. Именованный эквивалентен отсутствию атрибутов.
createSubcontext()иbind()отличается, он создает новый объект, например, новый контекст для привязки к каталогу, ноbind()Данный объект привязан к каталогу.
создать контекст
Чтобы создать контекст именования, выcreateSubcontext()Укажите имя создаваемого контекста. Чтобы создать контекст атрибута, вызовитеDirContext.createSubcontext()Укажите имя контекста, который вы хотите создать, и необходимые свойства.
прежде чем продолжить: примеры в этом руководстве требуют внесения дополнительных изменений в схему. ты должен закрытьLDAPОбнаружение схемы сервера или добавление схемы, соответствующей этому руководству, на сервер. Обычно эту работу выполняют администраторы сервера каталогов. Пожалуйста, посмотрите курс.
// Create attributes to be associated with the new context Attributes attrs = new BasicAttributes(true); // case-ignore Attribute objclass = new BasicAttribute("objectclass"); objclass.add("top"); objclass.add("organizationalUnit"); attrs.put(objclass);
// Create the context Context result = ctx.createSubcontext("NewOu", attrs); |
В этом примере создается имя "ou=NewO"контекст и имеет атрибуты"objectclass",Атрибуты"top"и"organizationalUnit",в"objectclass"имеет два значения.
# java Create ou=Groups: javax.naming.directory.DirContext ou=People: javax.naming.directory.DirContext ou=NewOu: javax.naming.directory.DirContext |
В этом примере создается новый контекст с именем "NewOu",Даctxподконтекст.
уничтожить контекст
Чтобы разрушить контекст, вам нужноdestroySubcontext()Укажите имя контекста, который необходимо уничтожить.
// Destroy the context ctx.destroySubcontext("NewOu"); |
Этот пример в контекстеctxудалить контекст"NewOu".
Имя свойства
Атрибут состоит из идентификатора атрибута и набора значений атрибута. Идентификатор атрибута называется именем атрибута, которое представляет собой строку, представляющую атрибут. Значением свойства является содержимое свойства, его тип не обязательно является строкой. Вы используете имя свойства, когда хотите указать получение, поиск или изменение определенного свойства. Имя также возвращается в операциях, которые возвращают атрибуты (например, когда вы выполняете операцию чтения или поиска в каталоге).
При использовании имен атрибутов вам необходимо знать характеристики конкретного сервера каталогов, чтобы результаты вас не удивили. Эти особенности описаны в следующем подразделе.
тип недвижимости
в таких какLDAPВ таких каталогах имя атрибута указывает тип атрибута, обычно называемый именем типа атрибута. Например, имя свойства "cn" также называется именем типа атрибута. Тип атрибута определяет синтаксис значения атрибута, допустимость нескольких значений, равенство и сопоставление при сравнении и сортировке значений атрибута,
подкласс собственности
Некоторые реализации каталогов поддерживают подтипы каталогов, то есть сервер позволяет типам атрибутов использовать определения других типов атрибутов. Например,"name" атрибуты могут быть всеnameСупертип связанного свойства: "commonName"Даnameподкласс . Для реализации каталога, поддерживающего этот tesnag, посетите "name"имущество может вернуться"commonName"Атрибуты.
При доступе к каталогу, поддерживающему подтипы свойств, имейте в виду, что сервер может вернуть тип, несовместимый с вашим запросом. Чтобы уменьшить этот шанс, используйте наиболее производный класс.
синоним имени свойства
Некоторые реализации каталогов поддерживают синонимы для имен атрибутов. Например,"cn"может быть"commonNameСиноним к слову "попросить"cn"имущество может вернуться"commonName"Атрибуты.
При доступе к каталогу, который поддерживает синонимы атрибутов, вы должны знать, что сервер может вернуть другое имя атрибута, чем вы запросили. Чтобы этого не произошло, используйте официальные имена свойств, а не синонимы. Официальное имя атрибута — это имя атрибута, которое определяет атрибут; синоним — это имя, которое ссылается на официальное имя атрибута в определении.
Языковое предпочтение
LDAP v3расширение (RFC 2596) позволяет указать кодировку языка вместе с именем свойства. Подобно свойствам подкласса, одно имя свойства может представлять несколько разных свойств. Например"description” имеет два разных языковых варианта:
description: software description;lang-en: software products description;lang-de: Softwareprodukte |
правильно"description" вернет все три атрибута. При доступе к каталогу, который поддерживает эту функцию, вы должны знать, что сервер может вернуть другое имя, чем было запрошено.
читать свойство
Чтобы прочитать свойства объекта из каталога, используйтеDirContext.getAttributes()И просто введите имя свойства, которое вы хотите прочитать. Предположим, что имя объекта в службе имен "cn=Ted Geisel, ou=People". Чтобы получить свойства объекта, используйте следующий код:
Attributes answer = ctx.getAttributes("cn=Ted Geisel, ou=People"); |
Вы можете распечатать содержание ответа следующим образом:
for (NamingEnumeration ae = answer.getAll(); ae.hasMore();) { Attribute attr = (Attribute)ae.next(); System.out.println("attribute: " + attr.getID()); /* Print each value */ for (NamingEnumeration e = attr.getAll(); e.hasMore(); System.out.println("value: " + e.next())) ; } |
Результат выглядит следующим образом:
# java GetattrsAll attribute: sn value: Geisel attribute: objectclass value: top value: person value: organizationalPerson value: inetOrgPerson attribute: jpegphoto value: [B@1dacd78b attribute: mail value: Ted.Geisel@JNDITutorial.com attribute: facsimiletelephonenumber value: +1 408 555 2329 attribute: telephonenumber value: +1 408 555 5252 attribute: cn value: Ted Geisel |
Вернуть выбранный атрибут
Чтобы прочитать свойства выбранного подмножества, вам необходимо предоставить массив идентификаторов свойств, которые вы хотите получить.
// Specify the ids of the attributes to return String[] attrIDs = {"sn", "telephonenumber", "golfhandicap", "mail"};
// Get the attributes requested Attributes answer = ctx.getAttributes("cn=Ted Geisel, ou=People", attrIDs); |
Этот пример объекта запроса"cn=Ted Geisel, ou=People"из"sn","telephonenumber","golfhandicap"и"mail", поэтому эти три атрибута возвращаются в ответе.
Вот результат:
# java Getattrs attribute: sn value: Geisel attribute: mail value: Ted.Geisel@JNDITutorial.com attribute: telephonenumber value: +1 408 555 5252 |
Изменить свойства
DirContextИнтерфейс содержит методы для изменения свойств и значений свойств объектов в каталоге.
Используйте список редактирования
Один из способов изменить свойства объекта — предоставить список модификаций (ModificationItem). КаждыйModificationItemСодержит числовые константы, указывающие тип модификации и описывающие свойства, которые необходимо изменить. Ниже приведены типы модификаций.
l ADD_ATTRIBUTE
l REPLACE_ATTRIBUTE
l REMOVE_ATTRIBUTE
Модификации выполняются с типами, представленными в списке. Либо выполняются все модификации, либо не выполняется ни одна из них.
Следующий код создает список модификаций. будет "mail” значение атрибута заменяется наgeisel@wizards.com,за"telephonenumber"свойство добавляет дополнительную ценность и удаляет"jpegphoto"Атрибуты.
// Specify the changes to make ModificationItem[] mods = new ModificationItem[3];
// Replace the "mail" attribute with a new value mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("mail", "geisel@wizards.com"));
// Add an additional value to "telephonenumber" mods[1] = new ModificationItem(DirContext.ADD_ATTRIBUTE, new BasicAttribute("telephonenumber", "+1 555 555 5555"));
// Remove the "jpegphoto" attribute mods[2] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, new BasicAttribute("jpegphoto")); |
WindowsАктивный каталог: Active Directory будет "telephonenumber” определяется как однозначный атрибут, который иRFC 2256не соответствует. Чтобы этот пример выполнялся в Active Directory, вы должны либо использовать другие атрибуты вместо «telephonenumber"или будетDirContext.ADD_ATTRIBUTEизменить наDirContext.REPLACE_ATTRIBUTE.
После создания списка редактирования вы можете предоставить егоmodifyAttributes():
// Perform the requested modifications on the named object ctx.modifyAttributes(name, mods); |
использовать атрибут
При желании вы можете изменить, указав тип модификации и изменив атрибут.
Например, в следующей строке используетсяorigсерединаnameСвяжите свойства, которые необходимо заменить:
ctx.modifyAttributes(name, DirContext.REPLACE_ATTRIBUTE, orig); |
Названия других свойств не изменились.
два дляmodifyAttributes()используются в примерах программ. Процедура модификации свойств с помощью списка модификаций находится во второй частиmodifyAttributes()восстановить первоначальные свойства.
Добавлять и удалять привязки со свойствами
Названные примеры обсуждают, как использоватьbind()иunbind(),DirContextПерегруженные версии этих двух методов. ты используешьDirContextМетоды связывают свойства объекта, добавляя их в пространство имен при привязке или подконтексте. Например, вы могли создатьPersonобъект, а затемPersonКогда объект связан со свойством, он привязывается к пространству имен.
Добавить привязки со свойствами
DirContext.bind()Используется для добавления привязок свойств к контексту. Его параметрами являются имя связываемого объекта и набор свойств.
// Create the object to be bound Fruit fruit = new Fruit("orange");
// Create attributes to be associated with the object Attributes attrs = new BasicAttributes(true); // case-ignore Attribute objclass = new BasicAttribute("objectclass"); objclass.add("top"); objclass.add("organizationalUnit"); attrs.put(objclass);
// Perform bind ctx.bind("ou=favorite, ou=Fruits", fruit, attrs); |
Этот пример создаетFruitобъект класса и привязать его к "ou=Fruits"контекст, названный"ou=favorite".Связать с "objectclass" свойство. Если рядом вctxЗапрос в "ou=favorite, ou=Fruits", то вы получитеfruitобъект. Хочешь - получай"ou=favorite, ou=Fruits", вы получите свойства, которые вы только что добавили к объекту. Вот результат примера:
# java Bind orange attribute: objectclass value: top value: organizationalUnit value: javaObject value: javaNamingReference attribute: javaclassname value: Fruit attribute: javafactory value: FruitFactory attribute: javareferenceaddress value: #0#fruit#orange attribute: ou value: favorite |
Показать больше, чем свойства используются для хранения информации об объекте (fruit) немного информации. Эта избыточная информация будет подробно описана позже.
Если вы запустите пример дважды, второй запуск завершится ошибкой с броскомNameAlreadyBoundException. Это потому что"ou=favorite"уже привязан к контексту"ou=Fruitsв. Чтобы добиться успеха, нужно использоватьrebind().
Заменить привязки свойствами
DirContext.rebind()Роль заключается в добавлении или изменении привязок и свойств. он принимает иbind()те же параметры. Однако, используяrebind()Если имя уже существует, оно сначалаUnbindЗатем привяжите новые объекты и свойства.
// Create the object to be bound Fruit fruit = new Fruit("lemon");
// Create attributes to be associated with the object Attributes attrs = new BasicAttributes(true); // case-ignore Attribute objclass = new BasicAttribute("objectclass"); objclass.add("top"); objclass.add("organizationalUnit"); attrs.put(objclass);
// Perform bind ctx.rebind("ou=favorite, ou=Fruits", fruit, attrs); |
При запуске этого примера он заменяетbind()Связь привязки, созданная в примере.
# java Rebind lemon attribute: objectclass value: top value: organizationalUnit value: javaObject value: javaNamingReference attribute: javaclassname value: Fruit attribute: javafactory value: FruitFactory attribute: javareferenceaddress value: #0#fruit#lemon attribute: ou value: favorite |
поиск
Наиболее полезным преимуществом, которое предоставляет каталог, является функция «Желтые страницы» или служба поиска. Вы можете составить запрос, включающий атрибуты элемента, а затем отправить запрос в каталог. Затем каталог возвращает список записей, удовлетворяющих запросу. Например, вы можете зайти в каталог и найти средние показатели по боулингу, превышающие200, или все фамилии заканчивающиеся на "Sch«Человек, который начал.
DirContextИнтерфейсы предоставляют методы для запроса записей, которые являются сложными и мощными. Различные аспекты поиска в каталогах описаны в следующих разделах:
l Базовый поиск
l поисковый фильтр
l управление поиском
Базовый поиск
Простейшие запросы требуют указания набора атрибутов, которые должна содержать запись, и целевого контекста, в котором выполняется запрос.
Следующий код создает коллекцию свойствmatchAttrs, который имеет два свойства"sn"и"mailЗаписи поиска по имени таблицы должны иметь фамилию (sn) свойство со значением "Geisel",а также"mail" свойство может быть любым значением. Затем вызовитеDirContext.search()контекст запроса"ou=People"нейтрализоватьmatchAttrsсоответствующая запись.
// Specify the attributes to match // Ask for objects that has a surname ("sn") attribute with // the value "Geisel" and the "mail" attribute Attributes matchAttrs = new BasicAttributes(true); // ignore attribute name case matchAttrs.put(new BasicAttribute("sn", "Geisel")); matchAttrs.put(new BasicAttribute("mail"));
// Search for objects that have those matching attributes NamingEnumeration answer = ctx.search("ou=People", matchAttrs);
You can then print the results as follows. while (answer.hasMore()) { SearchResult sr = (SearchResult)answer.next(); System.out.println(">>>" + sr.getName()); printAttrs(sr.getAttributes()); } |
printAttrs()Методы иgetAttributes()Аналогичным образом метод выводит коллекцию свойств.
Возвращаемые результаты следующие:
# java SearchRetAll >>>cn=Ted Geisel attribute: sn value: Geisel attribute: objectclass value: top value: person value: organizationalPerson value: inetOrgPerson attribute: jpegphoto value: [B@1dacd78b attribute: mail value: Ted.Geisel@JNDITutorial.com attribute: facsimiletelephonenumber value: +1 408 555 2329 attribute: cn value: Ted Geisel attribute: telephonenumber value: +1 408 555 5252 |
Вернуть выбранный атрибут
В предыдущем примере возвращаются все атрибуты записей, которые удовлетворяют указанным критериям запроса. Вы можете пройтиsearch()Способ передачи массива идентификаторов атрибутов выбирает атрибуты, которые вы хотите включить в набор результатов. при созданииmatchAttrsТолько вы должны создать массив идентификаторов свойств, например:
// Specify the ids of the attributes to return String[] attrIDs = {"sn", "telephonenumber", "golfhandicap", "mail"};
// Search for objects that have those matching attributes NamingEnumeration answer = ctx.search("ou=People", matchAttrs, attrIDs); |
В этом примере возвращаются свойства записи"sn","telephonenumber","golfhandicap"а также"mail", где запись имеет атрибуты"mail"и"sn"Стоимость имущества"Geisel". Этот пример дает следующий результат. (В записи нет "golfhandicap" свойство, поэтому ничего не возвращается).
# java Search >>>cn=Ted Geisel attribute: sn value: Geisel attribute: mail value: Ted.Geisel@JNDITutorial.com attribute: telephonenumber value: +1 408 555 5252 |
фильтр
Помимо поиска по заданному набору свойств, вы можете осуществлять поиск в виде поисковых фильтров. Поисковый фильтр — это логическое выражение для поиска.DirContext.search()Допустимый синтаксис фильтра находится вRFC 2254определено в.
Следующий поисковый фильтр указывает, что записи, удовлетворяющие запросу, должны иметь значение "Geisel"из"sn"свойство, а значение произвольное"mail"Атрибуты:
(&(sn=Geisel)(mail=*)) |
Следующий код создает фильтр вместе со значением по умолчанию.SearchControls, используйте их для выполнения запросов. Результат этого запроса такой же, как и в базовом запросе.
// Create the default search controls SearchControls ctls = new SearchControls();
// Specify the search filter to match // Ask for objects that have the attribute "sn" == "Geisel" // and the "mail" attribute String filter = "(&(sn=Geisel)(mail=*))";
// Search for objects using the filter NamingEnumeration answer = ctx.search("ou=People", filter, ctls); |
Результаты поиска следующие:
# java SearchWithFilterRetAll >>>cn=Ted Geisel attribute: sn value: Geisel attribute: objectclass value: top value: person value: organizationalPerson value: inetOrgPerson attribute: jpegphoto value: [B@1dacd75e attribute: mail value: Ted.Geisel@JNDITutorial.com attribute: facsimiletelephonenumber value: +1 408 555 2329 attribute: cn value: Ted Geisel attribute: telephonenumber value: +1 408 555 5252 |
поискфильтрОбзор синтаксиса
Фильтр поиска — это поисковое выражение с префиксом (выражению предшествуют логические операторы). В следующей таблице перечислены символы, используемые для создания фильтров.
символ |
описывать |
& |
с (все элементы в списке должны бытьtrue) |
| |
или (хотя бы один из списка должен бытьtrue) |
! |
нет (отрицательный термин не может бытьtrue) |
= |
Равно (в соответствии с правилами сопоставления атрибутов) |
~= |
примерно равно (в соответствии с правилами соответствия атрибута) |
>= |
Больше чем (в соответствии с правилами соответствия атрибута) |
<= |
меньше чем (на основе правил сопоставления атрибутов) |
=* |
существует (этот атрибут должен существовать в записи, но его значение не ограничено) |
* |
Подстановочные знаки (указывающие, что в этой позиции может быть один или несколько символов), используемые при указании значений атрибутов. |
\ |
Экранирующий символ (при встрече с "*", "(", ")" экранированы) |
Каждая запись в фильтре состоит из идентификатора атрибута и значения атрибута или символического представления значения атрибута. Например, пункт «sn=Geisel"Выражать"sn"Стоимость имущества должна быть"Geisel", а срок "mail=*"Выражать"mail"собственность должна существовать.
Каждый элемент должен быть заключен в круглые скобки, например, "(sn=Geisel)В этих терминах используются логические операторы, такие как&, создайте логические выражения, такие как "(& (sn=Geisel) (mail=*))".
Каждое логическое выражение может быть дополнительно составлено из других терминов, таких как «(| (& (sn=Geisel) (mail=*)) (sn=L*))". В этом примере запрашивается запись, которая либо содержит значение "Geisel"из"sn"имущество и"mail"собственность или"sn"атрибуты начинаются с букв"L"начало.
Подробное описание синтаксиса см.RFC 2254.
Вернуть выбранный атрибут
Предыдущий пример возвращает все атрибуты в записях, которые удовлетворяют заданному фильтру. Вы можете выбрать возвращаемые свойства, установив метод параметра управления поиском. Вы создаете набор идентификаторов свойств, которые хотите включить в результат, а затем передаете его вSearchControls.setReturningAttributes()середина. Следующее:
// Specify the ids of the attributes to return String[] attrIDs = {"sn", "telephonenumber", "golfhandicap", "mail"}; SearchControls ctls = new SearchControls(); ctls.setReturningAttributes(attrIDs); |
Этот пример соответствует разделу «Возврат выбранных свойств» раздела «Основной поиск». Результат после запуска следующий. (Эта запись не имеет "golfhandicap" свойство, поэтому ничего не возвращается).
# java SearchWithFilter >>>cn=Ted Geisel attribute: sn value: Geisel attribute: mail value: Ted.Geisel@JNDITutorial.com attribute: telephonenumber value: +1 408 555 5252 |
Сфера
дефолтSearchControlsУказывает, что поиск выполняется только в пространствах имен (SearchControls.ONELEVEL_SCOPE). Этот параметр по умолчанию используется в разделе «Фильтры поиска».
В дополнение к параметрам по умолчанию вы можете указать, что поиск будет выполняться по всему поддереву или только по именованным объектам.
поддерево поиска
Поиск по всему поддереву ищет не только именованный объект, но и его потомков. Для поиска таким способом перейдите наSearchControls.setSearchScope()пройти вSearchControls.SUBTREE_SCOPEпараметр:
// Specify the ids of the attributes to return String[] attrIDs = {"sn", "telephonenumber", "golfhandicap", "mail"}; SearchControls ctls = new SearchControls(); ctls.setReturningAttributes(attrIDs); ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
// Specify the search filter to match // Ask for objects that have the attribute "sn" == "Geisel" // and the "mail" attribute String filter = "(&(sn=Geisel)(mail=*))";
// Search the subtree for objects by using the filter NamingEnumeration answer = ctx.search("", filter, ctls); |
Этот пример искалctxПоддерево контекста для получения записей, удовлетворяющих фильтру поиска. Он находит в поддереве "cn= Ted Geisel, ou=People"Вход.
# java SearchSubtree >>>cn=Ted Geisel, ou=People attribute: sn value: Geisel attribute: mail value: Ted.Geisel@JNDITutorial.com attribute: telephonenumber value: +1 408 555 5252 |
Поиск именованных объектов
Вы также можете искать именованные объекты. Это полезно, например, для проверки того, удовлетворяет ли именованный объект фильтру поиска. Для поиска именованных объектов используйтеSearchControls.OBJECT_SCOPEперейти кsetSearchScope()середина.
// Specify the ids of the attributes to return String[] attrIDs = {"sn", "telephonenumber", "golfhandicap", "mail"}; SearchControls ctls = new SearchControls(); ctls.setReturningAttributes(attrIDs); ctls.setSearchScope(SearchControls.OBJECT_SCOPE);
// Specify the search filter to match // Ask for objects that have the attribute "sn" == "Geisel" // and the "mail" attribute String filter = "(&(sn=Geisel)(mail=*))";
// Search the subtree for objects by using the filter NamingEnumeration answer = ctx.search("cn=Ted Geisel, ou=People", filter, ctls); |
Этот пример проверяет, является ли объект "cn=Ted Geisel, ou=People"удовлетворяет заданному фильтру.
# java SearchObject >>> attribute: sn value: Geisel attribute: mail value: Ted.Geisel@JNDITutorial.com attribute: telephonenumber value: +1 408 555 5252 |
Пример находит результат и печатает его. Обратите внимание, что поле имени в результате пусто. Потому что имя объекта — это контекст, в котором делается запрос (cn=Ted Geisel, ou=People).
количество результатов
Иногда запрос может возвращать слишком много результатов, и вы хотите ограничить размер набора результатов. На этом этапе вы можете использовать ограниченное количество элементов управления поиском. По умолчанию поиск не ограничен — он вернет все найденные результаты. Чтобы установить ограничение на количество поисков, передайте число вSearchControls.setCountLimit()середина.
В следующем примере устанавливается максимальное число1.
// Set the search controls to limit the count to 1 SearchControls ctls = new SearchControls(); ctls.setCountLimit(1); |
Выдает, если программа пытается получить больше результатовSizeLimitExceededException. Если программа устанавливает ограничение, то либо комбинируйте это исключение сNamingExceptionsИсключения обрабатываются по-разному или в соответствии с размером предельного числа, и результаты, превышающие число, не запрашиваются.
Удовлетворение ограничения на количество поисков — это способ контролировать, как ваша программа потребляет ресурсы (такие как память и пропускная способность сети). Другие способы управления ресурсами — попытаться использовать небольшие поисковые фильтры, начать поиск в правильном контексте и использовать правильную область.
лимит времени
Ограничение времени поиска — это верхний предел времени, в течение которого операция поиска может ожидать ответа. Это полезно, когда вы не хотите слишком долго ждать ответа. Если операция поиска превышает лимит времени и не завершена, она выдаетTimeLimitExceededExceptionаномальный.
Чтобы установить ограничение по времени для поиска, передайте количество миллисекунд вSearchControls.setTimeLimit()Вот и все. В следующем примере устанавливается ограничение времени на1второй.
// Set the search controls to limit the time to 1 second (1000 ms) SearchControls ctls = new SearchControls(); ctls.setTimeLimit(1000); |
Чтобы запустить этот пример с тайм-аутом, потребуется реконфигурация либо с использованием медленного сервера, либо с использованием сервера с большим количеством записей. Вы также можете использовать другие способы сделать поиск более1второй.
ограничение по времени0Указывает, что ограничения по времени нет, поэтому запрос будет ждать неопределенное время.
Часто задаваемые вопросы
когда вы используетеJNDIОсновные проблемы, с которыми может столкнуться класс при запуске успешно скомпилированной программы, следующие:
l нет контекста инициализации
l В соединении отказано
l Ошибка подключения
l программа зависает
l имя не найдено
l Не могу подключиться ни к одному хосту
l Невозможно настроить свойства системы доступа
l Не работаетCRAM-MD5Сертификация
1. получитьNoInitialContextException
причина: вы не указали используемый контекст инициализации. специальный,Context.INITIAL_CONTEXT_FACTORYПеременная среды не задана как имя фабричного класса, который инициализирует контекст. последний не нашелContext.INITIAL_CONTEXT_FACTORYНастроены доступные поставщики услуг.
решение: установить переменную средыContext.INITIAL_CONTEXT_FACTORYУстановите имя класса контекста инициализации, которое вы используете. Подробнее см. в разделе Конфигурация.
Если свойство установлено, убедитесь, что имя класса не опечатка и класс виден в вашей программе (или вclasspathв или вJREизjre/lib/extПод содержанием).JavaПлатформа содержит поставщиков услуг сLDAP,COSназвание,DNSа такжеRMIрегистр. Все остальные поставщики услуг должны быть установлены и добавлены в среду выполнения.
2. получитьCommunicationExceptionИсключение, говорящее «Соединение отклонено».
причина:Context.PROVIDER_URLСервер и порт, указанные в параметрах среды, не предоставляют доступ. Кто-то мог отключить или закрыть службу. Или было введено неправильное имя сервера или номер порта.
решение: Убедитесь, что служба действительно работает на порту, и при необходимости перезапустите сервер. Эта проверка зависит от того, что вы используетеLDAPсервер. Как правило, сервером можно управлять с помощью административной консоли или инструментов. Вы можете использовать этот инструмент для подтверждения состояния сервера.
3. LDAPСервер отвечает на другие инструменты (такие как консоль управления), но не на запросы вашей программы.
причина: сервер не ответилLDAP v3Подключение полностью шаровой с подсветкой. Некоторые серверы (особенно общедоступные серверы) не отвечают правильноLDAP v3, используйте игнорировать вместо отклонения. В то же время некоторыеLDAP v3На сервере есть механизм обработки ошибок,SunизLDAPПоставщик услуг автоматически отправляет и обычно возвращает определенный код ошибки сервера.
решение: попробуйте установить параметры среды"java.naming.ldap.version"за"2".LDAPПоставщик услуг пытается использовать по умолчаниюLDAP v3соединятьLDAPсервер, затем используйтеLDAP v2. Если сервер молча игнорируетv3запрос, провайдер предполагает, что запрос действителен. Для такого типа сервера необходимо явно указать версию протокола, чтобы обеспечить правильное поведение сервера.
если серверv3server, затем попробуйте установить эти параметры среды перед созданием контекста инициализации:
env.put(Context.REFERRAL, "throw"); |
Это закрытоLDAPЭлементы управления автоматически отправляются провайдером (дополнительную информацию см.JNDIруководство).
4. Программа зависает.
причина: сервер (особенно общедоступный) не отвечает (не является ответом об ошибке), когда проверка, которую вы пытаетесь выполнить, дает слишком много результатов или требует, чтобы сервер запрашивал много записей для получения результата. Таким образом, сервер вычисляет затраты на основе предварительных запросов, пытаясь снизить потребление ресурсов.
Кроме того, вы пытаетесь использовать Secure Sockets Layer (SSL) но сервер/порт не поддерживается и наоборот (вы пытаетесь использовать обычный сокет сSSLдиалоговое окно порта).
В итоге сервер либо очень медленно отвечает из-за нагрузки, либо вообще не отвечает на некоторые запросы.
решение: если программа зависает из-за того, что сервер пытается снизить потребление ресурсов, повторите запрос с одним или несколькими ответами. Это может помочь вам определить, активен ли сервер. Таким образом, вы можете расширить исходный запрос и повторно отправить его.
Если ваша программаSSLпроблема висит, то нужно найтиSSLПосле этого порт установлен правильноContext.SECURITY_PROTOCOLПараметры окружающей среды. если портSSLпорт, то этот параметр должен быть установлен в "ssl".если неSSLпорт, этот параметр не должен быть установлен.
Если программа зависает не по вышеуказанным причинам, используйтеcom.sun.jndi.ldap.read.timeoutУказывает тайм-аут чтения. Значение этого параметра представляет собой строку, представляющуюLDAPВремя ожидания чтения запроса в миллисекундах. еслиLDAPЕсли провайдер не может получить ответ в течение цикла, попытка чтения отбрасывается. число должно быть больше, чем0. равно или меньше0Указывает, что период ожидания чтения не указан, что равно бесконечному ожиданию ответа.
Если этот параметр не указан, по умолчанию будет ожидаться ответ.
Например:
env.put("com.sun.jndi.ldap.read.timeout", "5000"); |
означает, еслиLDAPСервер не может быть5ответ в течение нескольких секунд, запрос на чтение будет отклонен.
5. ты получаешьNameNotFoundExceptionаномальный.
причина: когда выLDAPНачальный контекст инициализируется, предоставляется корневое различающееся имя. Например, если вы установите для начального контекстаContext.PROVIDER_URLза"ldap://ldapserver:389/o=JNDITutorial", затем укажите имя"cn=Joe,c=us", затем выLDAPПолное наименование службы доставки: "cn=Joe,c=us,o=JNDITutorial". Если это действительно то имя, которое вам нужно, то вам следует убедиться, что сервер содержит эту запись.
Кроме того, если вы укажете неправильное отличительное имя при аутентификации,Sun JavaСервер каталогов возвратил ошибку. Например, если вы установитеContext.SECURITY_PRINCIPAL Параметр среды "cn=Admin, o=Tutorial",и"cn=Admin, o=Tutorial"нетLDAPвход на сервер,LDAPпровайдер собирается броситьNameNotFoundException.Sun JavaТо, что вернул сервер каталогов, на самом деле было некоторым исключением проверки подлинности, а не "name not found".
решение: Подтвердите, что указанное вами имя существует на сервере. Вы можете подтвердить это, перечислив все записи в родительском контексте или используя другие инструменты, такие как консоль администратора сервера.
Развернуто следующееappletпроблемы, с которыми можно столкнуться.
6. Когда вашappletЯ получаю при попытке подключения к серверу каталоговAppletSecurityExceptionисключение, сервер работает и загружаетappletна разных машинах.
причина:appletПодписи нет, поэтому можно подключиться только к той машине, где она загружена. или еслиappetПодписано, не предоставлено браузеромappletРазрешение на подключение к серверу каталогов.
решение: если вы хотите разрешитьappletЧтобы подключиться к серверу каталогов на любой машине, вам необходимо подписать весьappletа такжеappletв использованииJNDI jar. оjar, см. Подпись и проверкаjarдокумент.
7. Когда вашappletПоявляется при попытке установить свойства среды с помощью системных свойств.AppletSecurityExceptionаномальный.
причина: браузер ограничивает доступ к системным параметрам и выкидывает при попытке чтенияSecurityException.
решение: Если вам нужноappletполучить ввод, попробуйте использоватьapplet paramsзаменять.
8. когдаappletБегFirefoxпопробуй использоватьCRAM-MD5В направленииLDAPВыбрасывается при аутентификацииAppletSecurityException.
причина:FirefoxНет доступаjava.securityСумка.LDAPпровайдер используетjava.security.MessageDigestПредоставляет функцию сводки информации для достиженияCRAM-MD5.
решение:использоватьJavaплагин.