You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by ak...@apache.org on 2004/06/24 09:06:37 UTC
svn commit: rev 21633 - in incubator/directory/eve/branches/start: . docs docs/design docs/issues src src/antlr src/conf src/docbook src/docbook/design src/docbook/design/operations src/images src/java src/java/org src/java/org/apache src/java/org/apache/eve src/java/org/apache/eve/backend src/java/org/apache/eve/backend/jdbm src/java/org/apache/eve/backend/jdbm/gui src/java/org/apache/eve/backend/jdbm/index src/java/org/apache/eve/backend/jdbm/search src/java/org/apache/eve/backend/jdbm/table src/java/org/apache/eve/backend/sql src/java/org/apache/eve/client src/java/org/apache/eve/decoder src/java/org/apache/eve/encoder src/java/org/apache/eve/event src/java/org/apache/eve/event/protocol src/java/org/apache/eve/input src/java/org/apache/eve/jndi src/java/org/apache/eve/listener src/java/org/apache/eve/output src/java/org/apache/eve/protocol src/java/org/apache/eve/protocol/event src/java/org/apache/eve/protocol/extended src/java/org/apache/eve/schema src/java/org/apache/eve/security src/java/org/apache/eve/security/auth src/java/org/apache/eve/seda src/ldif src/schema src/xdocs src/xdocs/images src/xdocs/images/design xdocs xdocs/design xdocs/design/operations xdocs/stylesheets
Author: akarasulu
Date: Thu Jun 24 00:06:35 2004
New Revision: 21633
Added:
incubator/directory/eve/branches/start/
incubator/directory/eve/branches/start/.classpath
incubator/directory/eve/branches/start/.cvsignore
incubator/directory/eve/branches/start/.project
incubator/directory/eve/branches/start/ChangeLog.txt (contents, props changed)
incubator/directory/eve/branches/start/LICENSE.txt (contents, props changed)
incubator/directory/eve/branches/start/SearchProblems.txt (contents, props changed)
incubator/directory/eve/branches/start/build.xml (contents, props changed)
incubator/directory/eve/branches/start/default.properties
incubator/directory/eve/branches/start/docs/
incubator/directory/eve/branches/start/docs/design/
incubator/directory/eve/branches/start/docs/issues/
incubator/directory/eve/branches/start/docs/issues/normalization.txt (contents, props changed)
incubator/directory/eve/branches/start/maven.xml (contents, props changed)
incubator/directory/eve/branches/start/project.properties
incubator/directory/eve/branches/start/project.xml (contents, props changed)
incubator/directory/eve/branches/start/sample.ant.properties
incubator/directory/eve/branches/start/sample.build.properties
incubator/directory/eve/branches/start/src/
incubator/directory/eve/branches/start/src/antlr/
incubator/directory/eve/branches/start/src/antlr/schema.g
incubator/directory/eve/branches/start/src/conf/
incubator/directory/eve/branches/start/src/conf/assembly.xml (contents, props changed)
incubator/directory/eve/branches/start/src/conf/config.xml (contents, props changed)
incubator/directory/eve/branches/start/src/conf/environment.xml (contents, props changed)
incubator/directory/eve/branches/start/src/docbook/
incubator/directory/eve/branches/start/src/docbook/design/
incubator/directory/eve/branches/start/src/docbook/design/authentication-module.xml (contents, props changed)
incubator/directory/eve/branches/start/src/docbook/design/backend-module.xml (contents, props changed)
incubator/directory/eve/branches/start/src/docbook/design/client-module.xml (contents, props changed)
incubator/directory/eve/branches/start/src/docbook/design/controls.xml (contents, props changed)
incubator/directory/eve/branches/start/src/docbook/design/decoder-module.xml (contents, props changed)
incubator/directory/eve/branches/start/src/docbook/design/encoder-module.xml (contents, props changed)
incubator/directory/eve/branches/start/src/docbook/design/event-module.xml (contents, props changed)
incubator/directory/eve/branches/start/src/docbook/design/input-module.xml (contents, props changed)
incubator/directory/eve/branches/start/src/docbook/design/jndi-provider-module.xml (contents, props changed)
incubator/directory/eve/branches/start/src/docbook/design/listener-module.xml (contents, props changed)
incubator/directory/eve/branches/start/src/docbook/design/module-implementation-template.xml (contents, props changed)
incubator/directory/eve/branches/start/src/docbook/design/nexus-module.xml (contents, props changed)
incubator/directory/eve/branches/start/src/docbook/design/operations/
incubator/directory/eve/branches/start/src/docbook/design/operations/opertion-template.xml (contents, props changed)
incubator/directory/eve/branches/start/src/docbook/design/operations/search-operation.xml (contents, props changed)
incubator/directory/eve/branches/start/src/docbook/design/output-module.xml (contents, props changed)
incubator/directory/eve/branches/start/src/docbook/design/protocol-module.xml (contents, props changed)
incubator/directory/eve/branches/start/src/docbook/design/request-session-scopes.xml (contents, props changed)
incubator/directory/eve/branches/start/src/docbook/design/rootdse-design.xml (contents, props changed)
incubator/directory/eve/branches/start/src/docbook/design/schema-module.xml (contents, props changed)
incubator/directory/eve/branches/start/src/docbook/design/seda-implementation.xml (contents, props changed)
incubator/directory/eve/branches/start/src/docbook/design/server-architecture.xml (contents, props changed)
incubator/directory/eve/branches/start/src/docbook/design/triggers-and-procedures.xml (contents, props changed)
incubator/directory/eve/branches/start/src/images/
incubator/directory/eve/branches/start/src/images/AddRequestProcessorProcess.gif (contents, props changed)
incubator/directory/eve/branches/start/src/images/AdminSchemaContext.gif (contents, props changed)
incubator/directory/eve/branches/start/src/images/BackendInterfaces.gif (contents, props changed)
incubator/directory/eve/branches/start/src/images/BindRequestProcessorProcess.gif (contents, props changed)
incubator/directory/eve/branches/start/src/images/CRUDLifecycle.gif (contents, props changed)
incubator/directory/eve/branches/start/src/images/CompareRequestProcessorProcess.gif (contents, props changed)
incubator/directory/eve/branches/start/src/images/DelRequestProcessorProcess.gif (contents, props changed)
incubator/directory/eve/branches/start/src/images/ExtendedRequestProcessorProcess.gif (contents, props changed)
incubator/directory/eve/branches/start/src/images/InputEventHandlerHandleEvent.gif (contents, props changed)
incubator/directory/eve/branches/start/src/images/InputModuleRegister.gif (contents, props changed)
incubator/directory/eve/branches/start/src/images/ListenerModuleRun.gif (contents, props changed)
incubator/directory/eve/branches/start/src/images/ModifyDNRequestProcessorProcess.gif (contents, props changed)
incubator/directory/eve/branches/start/src/images/ModifyRequestProcessorProcess.gif (contents, props changed)
incubator/directory/eve/branches/start/src/images/ModuleDependencies.gif (contents, props changed)
incubator/directory/eve/branches/start/src/images/OutputEventHandlerHandleEvent.gif (contents, props changed)
incubator/directory/eve/branches/start/src/images/OutputModuleWrite.gif (contents, props changed)
incubator/directory/eve/branches/start/src/images/ReqRespStageFlow.gif (contents, props changed)
incubator/directory/eve/branches/start/src/images/RequestEventHandlerHandleEvent.gif (contents, props changed)
incubator/directory/eve/branches/start/src/images/ResponseEventHandlerHandleEvent.gif (contents, props changed)
incubator/directory/eve/branches/start/src/images/SearchRequestProcessorProcess.gif (contents, props changed)
incubator/directory/eve/branches/start/src/images/UnBindRequestProcessorProcess.gif (contents, props changed)
incubator/directory/eve/branches/start/src/java/
incubator/directory/eve/branches/start/src/java/org/
incubator/directory/eve/branches/start/src/java/org/apache/
incubator/directory/eve/branches/start/src/java/org/apache/eve/
incubator/directory/eve/branches/start/src/java/org/apache/eve/AbstractModule.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/Kernel.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/Module.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/AtomicBackend.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/AttributeAdapter.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/AttributesAdapter.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/Backend.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/BackendConfig.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/BackendException.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/BackendModule.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/Cursor.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/CursorEvent.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/CursorException.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/CursorListener.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/EmptyCursor.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/EnumerationCursor.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/IteratorCursor.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/LdapEntry.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/NexusModule.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/NormalizerComponent.gif (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/ReadOnlyException.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/RootDSE.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/SingletonCursor.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/UnifiedBackend.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/backendhowto.html
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/contract.html
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/dnnormalization.html
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/Database.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/EntryCursor.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/IndexNotFoundException.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/JdbmDatabase.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/JdbmModule.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/LdapEntryImpl.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/gui/
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/gui/ASTNode.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/gui/AboutDialog.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/gui/AnnotatedFilterTreeDialog.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/gui/BackendFrame.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/gui/EntryNode.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/gui/FilterDialog.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/gui/IndexDialog.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/gui/JdbmBackendViewer.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/gui/JdbmTableModel.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/gui/MultiMapModel.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/gui/SearchResultDialog.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/gui/ldapd.gif (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/index/
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/index/BigIntegerComparator.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/index/Index.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/index/IndexComparator.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/index/IndexCursor.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/index/IndexRecord.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/index/JdbmIndex.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/index/StringComparator.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/search/
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/search/Assertion.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/search/DefaultOptimizer.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/search/DisjunctionCursor.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/search/Optimizer.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/search/PrefetchCursor.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/search/SearchEngine.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/table/
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/table/DupsCursor.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/table/JdbmTable.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/table/KeyOnlyComparator.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/table/MasterTable.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/table/NoDupsCursor.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/table/Table.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/table/TableComparator.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/table/TupleComparator.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/table/TupleIteratorCursor.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/table/TupleRenderer.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/package.html
incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/sql/
incubator/directory/eve/branches/start/src/java/org/apache/eve/client/
incubator/directory/eve/branches/start/src/java/org/apache/eve/client/ClientException.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/client/ClientKey.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/client/ClientManager.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/client/ClientManagerSlave.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/client/ClientModule.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/client/ClientSession.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/client/KeyExpiryException.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/client/LdapClientSession.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/client/ServerConfig.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/decoder/
incubator/directory/eve/branches/start/src/java/org/apache/eve/decoder/Decoder.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/decoder/DecoderException.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/decoder/DecoderModule.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/encoder/
incubator/directory/eve/branches/start/src/java/org/apache/eve/encoder/Encoder.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/encoder/EncoderException.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/encoder/EncoderModule.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/event/
incubator/directory/eve/branches/start/src/java/org/apache/eve/event/AbstractEventHandler.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/event/AuthenticationEvent.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/event/AuthenticationListener.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/event/ClientEvent.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/event/ClientListener.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/event/ConnectEvent.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/event/ConnectListener.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/event/EntryEvent.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/event/EntryEventSource.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/event/EntryListener.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/event/EventHandler.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/event/InputEvent.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/event/InputListener.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/event/OutputEvent.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/event/OutputListener.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/event/RequestEvent.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/event/RequestListener.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/event/ResponseEvent.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/event/ResponseListener.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/
incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/AbandonEvent.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/AddEvent.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/BindEvent.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/CompareEvent.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/DelEvent.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/EventManager.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/EventModule.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/ExtendedEvent.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/ModifyDnEvent.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/ModifyEvent.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/ProtocolAdapter.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/ProtocolEvent.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/ProtocolListener.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/SearchEvent.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/UnbindEvent.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/input/
incubator/directory/eve/branches/start/src/java/org/apache/eve/input/InputManager.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/input/InputModule.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/jndi/
incubator/directory/eve/branches/start/src/java/org/apache/eve/jndi/BindingEnumeration.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/jndi/ContextHelper.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/jndi/DirContextHelper.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/jndi/JndiProvider.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/jndi/JndiProviderModule.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/jndi/NameClassPairEnumeration.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/jndi/SearchResultEnumeration.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/jndi/ServerContextFactory.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/jndi/UnifiedContext.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/jndi/UnifiedDirContext.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/jndi/UnifiedLdapContext.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/listener/
incubator/directory/eve/branches/start/src/java/org/apache/eve/listener/ListenerException.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/listener/ListenerModule.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/listener/ServerListener.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/output/
incubator/directory/eve/branches/start/src/java/org/apache/eve/output/OutputManager.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/output/OutputModule.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/
incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/AbandonHandler.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/AddHandler.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/BindHandler.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/CompareHandler.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/DeleteHandler.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/ExtendedHandler.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/HandlerTypeEnum.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/ModifyDNRequestProcessor.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/ModifyDnHandler.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/ModifyHandler.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/NoReplyHandler.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/ProtocolEngine.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/ProtocolException.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/ProtocolModule.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/RequestHandler.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/SearchHandler.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/SearchRequestProcessor.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/SingleReplyHandler.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/Stats.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/UnbindHandler.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/Utils.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/event/
incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/extended/
incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/extended/PayloadHandler.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/schema/
incubator/directory/eve/branches/start/src/java/org/apache/eve/schema/AttributeSpec.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/schema/Normalizer.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/schema/ObjectClassSpec.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/schema/ParserSyntaxChecker.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/schema/RegexNormalizer.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/schema/RegexSyntaxChecker.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/schema/Schema.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/schema/SchemaImpl.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/schema/SchemaManager.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/schema/SchemaModule.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/schema/SyntaxChecker.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/security/
incubator/directory/eve/branches/start/src/java/org/apache/eve/security/LdapPrincipal.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/security/auth/
incubator/directory/eve/branches/start/src/java/org/apache/eve/security/auth/AuthenticationException.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/security/auth/AuthenticationManager.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/security/auth/AuthenticationModule.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/seda/
incubator/directory/eve/branches/start/src/java/org/apache/eve/seda/AbstractStage.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/seda/EnqueuePredicate.java (contents, props changed)
incubator/directory/eve/branches/start/src/java/org/apache/eve/seda/Stage.java (contents, props changed)
incubator/directory/eve/branches/start/src/ldif/
incubator/directory/eve/branches/start/src/ldif/addAll.ldif (contents, props changed)
incubator/directory/eve/branches/start/src/ldif/addRoot.ldif (contents, props changed)
incubator/directory/eve/branches/start/src/ldif/addTestUser.ldif (contents, props changed)
incubator/directory/eve/branches/start/src/ldif/example.ldif (contents, props changed)
incubator/directory/eve/branches/start/src/ldif/ori_example.ldif (contents, props changed)
incubator/directory/eve/branches/start/src/ldif/smallest_example.ldif (contents, props changed)
incubator/directory/eve/branches/start/src/schema/
incubator/directory/eve/branches/start/src/schema/corba.schema
incubator/directory/eve/branches/start/src/schema/core.schema
incubator/directory/eve/branches/start/src/schema/core.xml (contents, props changed)
incubator/directory/eve/branches/start/src/schema/cosine.schema
incubator/directory/eve/branches/start/src/schema/inetorgperson.schema
incubator/directory/eve/branches/start/src/schema/java.schema
incubator/directory/eve/branches/start/src/schema/krb5-kdc.schema
incubator/directory/eve/branches/start/src/schema/misc.schema
incubator/directory/eve/branches/start/src/schema/nis.schema
incubator/directory/eve/branches/start/src/schema/openldap.schema
incubator/directory/eve/branches/start/src/schema/our.schema
incubator/directory/eve/branches/start/src/schema/vendor.schema
incubator/directory/eve/branches/start/src/xdocs/
incubator/directory/eve/branches/start/src/xdocs/images/
incubator/directory/eve/branches/start/src/xdocs/images/design/
incubator/directory/eve/branches/start/todo.txt (contents, props changed)
incubator/directory/eve/branches/start/xdocs/
incubator/directory/eve/branches/start/xdocs/design/
incubator/directory/eve/branches/start/xdocs/design/operations/
incubator/directory/eve/branches/start/xdocs/design/operations/index.xml (contents, props changed)
incubator/directory/eve/branches/start/xdocs/design/operations/navigation.xml (contents, props changed)
incubator/directory/eve/branches/start/xdocs/devprocess.xml (contents, props changed)
incubator/directory/eve/branches/start/xdocs/index.xml (contents, props changed)
incubator/directory/eve/branches/start/xdocs/navigation.xml (contents, props changed)
incubator/directory/eve/branches/start/xdocs/stylesheets/
incubator/directory/eve/branches/start/xdocs/stylesheets/tigris.css
incubator/directory/eve/branches/start/xdocs/temp.xml (contents, props changed)
Log:
Initial Eve State on SVN Import - A MAINTENANCE BRANCH ONLY FOR BUG FIXES
Added: incubator/directory/eve/branches/start/.classpath
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/.classpath Thu Jun 24 00:06:35 2004
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<classpath>
+ <classpathentry kind="src" path="src/java">
+ </classpathentry>
+ <classpathentry kind="var" rootpath="JRE_SRCROOT" path="JRE_LIB" sourcepath="JRE_SRC">
+ </classpathentry>
+ <classpathentry kind="var" path="MAVEN_REPO/commons-logging/jars/commons-logging-1.0.2.jar">
+ </classpathentry>
+ <classpathentry kind="var" path="MAVEN_REPO/oro/jars/oro-2.0.7.jar">
+ </classpathentry>
+ <classpathentry kind="var" path="MAVEN_REPO/cornerstone-threads/jars/cornerstone-threads-impl-SNAPSHOT.jar">
+ </classpathentry>
+ <classpathentry kind="var" path="MAVEN_REPO/cornerstone-threads/jars/cornerstone-threads-api-SNAPSHOT.jar">
+ </classpathentry>
+ <classpathentry kind="var" path="MAVEN_REPO/excalibur-thread/jars/excalibur-thread-1.1.1.jar">
+ </classpathentry>
+ <classpathentry kind="var" path="MAVEN_REPO/avalon-phoenix/jars/avalon-phoenix-client-4.0.jar">
+ </classpathentry>
+ <classpathentry kind="var" path="MAVEN_REPO/ldapd-common/jars/ldapd-common-SNAPSHOT.jar">
+ </classpathentry>
+ <classpathentry kind="var" path="MAVEN_REPO/ldapd-snacc-provider/jars/ldapd-snacc-provider-SNAPSHOT.jar">
+ </classpathentry>
+ <classpathentry kind="var" path="MAVEN_REPO/commons-collections/jars/commons-collections-2.1.jar">
+ </classpathentry>
+ <classpathentry kind="var" path="MAVEN_REPO/regexp/jars/regexp-1.2.jar">
+ </classpathentry>
+ <classpathentry kind="var" path="MAVEN_REPO/antlr/jars/antlr-2.7.2.jar">
+ </classpathentry>
+ <classpathentry kind="var" path="MAVEN_REPO/avalon-framework/jars/avalon-framework-api-SNAPSHOT.jar">
+ </classpathentry>
+ <classpathentry kind="var" path="MAVEN_REPO/avalon-framework/jars/avalon-framework-impl-SNAPSHOT.jar">
+ </classpathentry>
+ <classpathentry kind="output" path="target/classes">
+ </classpathentry>
+</classpath>
\ No newline at end of file
Added: incubator/directory/eve/branches/start/.cvsignore
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/.cvsignore Thu Jun 24 00:06:35 2004
@@ -0,0 +1,22 @@
+*.twr
+*.tpr
+*.tws
+*.log
+*.db
+.nbattrs
+antlr*
+test*
+target
+dist
+build
+diagrams
+testdb*
+classes
+together
+build.properties
+together/newton/diagrams
+*javadocs
+SchemaParser.java
+SchemaSyntaxLexer.java
+SchemaTokenTypes.java
+SchemaTokenTypes.txt
Added: incubator/directory/eve/branches/start/.project
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/.project Thu Jun 24 00:06:35 2004
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<projectDescription>
+ <name>ldapd-server</name>
+ <comment>Common LDAP packages used for protocol compliant parsing of distinguished names, LDIFs, filters, and urls. Also contains the Common Message API which enables a plugable interface for ASN.1 BER Message providers.</comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
\ No newline at end of file
Added: incubator/directory/eve/branches/start/ChangeLog.txt
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/ChangeLog.txt Thu Jun 24 00:06:35 2004
@@ -0,0 +1,17 @@
+Release 0.71a
+=============
+
+* Refactored ClientKeys to throw KeyExpiryExceptions.
+* Modified OutputModule to handle expirations and it now buffers client writes.
+* Enabled use of IO lock objects in InputModule and DecoderModule.
+* InputModule's InputStreamMonitor now politely exits when the ClientKey is
+ expired rather than exiting due to an IOException on the InputStream.
+* Cleaned up the ClientManager interface and its ClientModule implementation
+ to enable named and anonymous sessions.
+* ClientModule now dependent on Nexus which has become a ClientManagerSlave
+ along with all backends.
+* ProtocolEngine now uses ClientManager interface methods to assiciate worker
+ threads with clients when they process requests on behalf of the client.
+* Added ability to transparently inject or alter operational attributes within
+ the nexus module.
+
Added: incubator/directory/eve/branches/start/LICENSE.txt
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/LICENSE.txt Thu Jun 24 00:06:35 2004
@@ -0,0 +1,204 @@
+/*
+ * Apache License
+ * Version 2.0, January 2004
+ * http://www.apache.org/licenses/
+ *
+ * TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+ *
+ * 1. Definitions.
+ *
+ * "License" shall mean the terms and conditions for use, reproduction,
+ * and distribution as defined by Sections 1 through 9 of this document.
+ *
+ * "Licensor" shall mean the copyright owner or entity authorized by
+ * the copyright owner that is granting the License.
+ *
+ * "Legal Entity" shall mean the union of the acting entity and all
+ * other entities that control, are controlled by, or are under common
+ * control with that entity. For the purposes of this definition,
+ * "control" means (i) the power, direct or indirect, to cause the
+ * direction or management of such entity, whether by contract or
+ * otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ * outstanding shares, or (iii) beneficial ownership of such entity.
+ *
+ * "You" (or "Your") shall mean an individual or Legal Entity
+ * exercising permissions granted by this License.
+ *
+ * "Source" form shall mean the preferred form for making modifications,
+ * including but not limited to software source code, documentation
+ * source, and configuration files.
+ *
+ * "Object" form shall mean any form resulting from mechanical
+ * transformation or translation of a Source form, including but
+ * not limited to compiled object code, generated documentation,
+ * and conversions to other media types.
+ *
+ * "Work" shall mean the work of authorship, whether in Source or
+ * Object form, made available under the License, as indicated by a
+ * copyright notice that is included in or attached to the work
+ * (an example is provided in the Appendix below).
+ *
+ * "Derivative Works" shall mean any work, whether in Source or Object
+ * form, that is based on (or derived from) the Work and for which the
+ * editorial revisions, annotations, elaborations, or other modifications
+ * represent, as a whole, an original work of authorship. For the purposes
+ * of this License, Derivative Works shall not include works that remain
+ * separable from, or merely link (or bind by name) to the interfaces of,
+ * the Work and Derivative Works thereof.
+ *
+ * "Contribution" shall mean any work of authorship, including
+ * the original version of the Work and any modifications or additions
+ * to that Work or Derivative Works thereof, that is intentionally
+ * submitted to Licensor for inclusion in the Work by the copyright owner
+ * or by an individual or Legal Entity authorized to submit on behalf of
+ * the copyright owner. For the purposes of this definition, "submitted"
+ * means any form of electronic, verbal, or written communication sent
+ * to the Licensor or its representatives, including but not limited to
+ * communication on electronic mailing lists, source code control systems,
+ * and issue tracking systems that are managed by, or on behalf of, the
+ * Licensor for the purpose of discussing and improving the Work, but
+ * excluding communication that is conspicuously marked or otherwise
+ * designated in writing by the copyright owner as "Not a Contribution."
+ *
+ * "Contributor" shall mean Licensor and any individual or Legal Entity
+ * on behalf of whom a Contribution has been received by Licensor and
+ * subsequently incorporated within the Work.
+ *
+ * 2. Grant of Copyright License. Subject to the terms and conditions of
+ * this License, each Contributor hereby grants to You a perpetual,
+ * worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ * copyright license to reproduce, prepare Derivative Works of,
+ * publicly display, publicly perform, sublicense, and distribute the
+ * Work and such Derivative Works in Source or Object form.
+ *
+ * 3. Grant of Patent License. Subject to the terms and conditions of
+ * this License, each Contributor hereby grants to You a perpetual,
+ * worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ * (except as stated in this section) patent license to make, have made,
+ * use, offer to sell, sell, import, and otherwise transfer the Work,
+ * where such license applies only to those patent claims licensable
+ * by such Contributor that are necessarily infringed by their
+ * Contribution(s) alone or by combination of their Contribution(s)
+ * with the Work to which such Contribution(s) was submitted. If You
+ * institute patent litigation against any entity (including a
+ * cross-claim or counterclaim in a lawsuit) alleging that the Work
+ * or a Contribution incorporated within the Work constitutes direct
+ * or contributory patent infringement, then any patent licenses
+ * granted to You under this License for that Work shall terminate
+ * as of the date such litigation is filed.
+ *
+ * 4. Redistribution. You may reproduce and distribute copies of the
+ * Work or Derivative Works thereof in any medium, with or without
+ * modifications, and in Source or Object form, provided that You
+ * meet the following conditions:
+ *
+ * (a) You must give any other recipients of the Work or
+ * Derivative Works a copy of this License; and
+ *
+ * (b) You must cause any modified files to carry prominent notices
+ * stating that You changed the files; and
+ *
+ * (c) You must retain, in the Source form of any Derivative Works
+ * that You distribute, all copyright, patent, trademark, and
+ * attribution notices from the Source form of the Work,
+ * excluding those notices that do not pertain to any part of
+ * the Derivative Works; and
+ *
+ * (d) If the Work includes a "NOTICE" text file as part of its
+ * distribution, then any Derivative Works that You distribute must
+ * include a readable copy of the attribution notices contained
+ * within such NOTICE file, excluding those notices that do not
+ * pertain to any part of the Derivative Works, in at least one
+ * of the following places: within a NOTICE text file distributed
+ * as part of the Derivative Works; within the Source form or
+ * documentation, if provided along with the Derivative Works; or,
+ * within a display generated by the Derivative Works, if and
+ * wherever such third-party notices normally appear. The contents
+ * of the NOTICE file are for informational purposes only and
+ * do not modify the License. You may add Your own attribution
+ * notices within Derivative Works that You distribute, alongside
+ * or as an addendum to the NOTICE text from the Work, provided
+ * that such additional attribution notices cannot be construed
+ * as modifying the License.
+ *
+ * You may add Your own copyright statement to Your modifications and
+ * may provide additional or different license terms and conditions
+ * for use, reproduction, or distribution of Your modifications, or
+ * for any such Derivative Works as a whole, provided Your use,
+ * reproduction, and distribution of the Work otherwise complies with
+ * the conditions stated in this License.
+ *
+ * 5. Submission of Contributions. Unless You explicitly state otherwise,
+ * any Contribution intentionally submitted for inclusion in the Work
+ * by You to the Licensor shall be under the terms and conditions of
+ * this License, without any additional terms or conditions.
+ * Notwithstanding the above, nothing herein shall supersede or modify
+ * the terms of any separate license agreement you may have executed
+ * with Licensor regarding such Contributions.
+ *
+ * 6. Trademarks. This License does not grant permission to use the trade
+ * names, trademarks, service marks, or product names of the Licensor,
+ * except as required for reasonable and customary use in describing the
+ * origin of the Work and reproducing the content of the NOTICE file.
+ *
+ * 7. Disclaimer of Warranty. Unless required by applicable law or
+ * agreed to in writing, Licensor provides the Work (and each
+ * Contributor provides its Contributions) on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied, including, without limitation, any warranties or conditions
+ * of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ * PARTICULAR PURPOSE. You are solely responsible for determining the
+ * appropriateness of using or redistributing the Work and assume any
+ * risks associated with Your exercise of permissions under this License.
+ *
+ * 8. Limitation of Liability. In no event and under no legal theory,
+ * whether in tort (including negligence), contract, or otherwise,
+ * unless required by applicable law (such as deliberate and grossly
+ * negligent acts) or agreed to in writing, shall any Contributor be
+ * liable to You for damages, including any direct, indirect, special,
+ * incidental, or consequential damages of any character arising as a
+ * result of this License or out of the use or inability to use the
+ * Work (including but not limited to damages for loss of goodwill,
+ * work stoppage, computer failure or malfunction, or any and all
+ * other commercial damages or losses), even if such Contributor
+ * has been advised of the possibility of such damages.
+ *
+ * 9. Accepting Warranty or Additional Liability. While redistributing
+ * the Work or Derivative Works thereof, You may choose to offer,
+ * and charge a fee for, acceptance of support, warranty, indemnity,
+ * or other liability obligations and/or rights consistent with this
+ * License. However, in accepting such obligations, You may act only
+ * on Your own behalf and on Your sole responsibility, not on behalf
+ * of any other Contributor, and only if You agree to indemnify,
+ * defend, and hold each Contributor harmless for any liability
+ * incurred by, or claims asserted against, such Contributor by reason
+ * of your accepting any such warranty or additional liability.
+ *
+ * END OF TERMS AND CONDITIONS
+ *
+ * APPENDIX: How to apply the Apache License to your work.
+ *
+ * To apply the Apache License to your work, attach the following
+ * boilerplate notice, with the fields enclosed by brackets "[]"
+ * replaced with your own identifying information. (Don't include
+ * the brackets!) The text should be enclosed in the appropriate
+ * comment syntax for the file format. We also recommend that a
+ * file or class name and description of purpose be included on the
+ * same "printed page" as the copyright notice for easier
+ * identification within third-party archives.
+ *
+ * Copyright [yyyy] [name of copyright owner]
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
Added: incubator/directory/eve/branches/start/SearchProblems.txt
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/SearchProblems.txt Thu Jun 24 00:06:35 2004
@@ -0,0 +1,59 @@
+ Problems With The Search Operation
+--------------------------------------------------------------
+
+* The following search parameters are not taken into account:
+
+ - timeLimit
+ - sizeLimit
+ - typesOnly
+ - derefAliases
+
+* Pruning of undefined filter assertions does not occur.
+ This must happen to facilitate the behavoir defined for
+ searches with invalid filter expressions in accordance
+ with RFC 2251.
+
+* Alias dereferencing obviously from the list above is not
+ supported at the present moment.
+
+* Referals are not supported at all by the search processor
+ at the present moment.
+
+* The search entry responses do not add binary flags in the
+ attribute description for binary attributes.
+
+* Note that all requests except for abandon and unbind (which
+ do not return responses) can return a referal to find the
+ target entry. Only the search requests manage the resolution
+ of referals and aliases.
+
+* Extensible matching is not enabled.
+
+* Undefined filter assertion pruning is not performed.
+
+* The attribute list to return is not supported and all
+ including operational attributes are returned. We need to
+ return all attributes (but not operational attributes) if
+ the attribute list is empty or has a "*" wild card (which
+ returns operational attributes as well.
+
+* Need to recognize the special reserved "1.1" attribute OID
+ in the attribute list to connotate the return of none of the
+ attributes in the entry.
+
+
+
+ Other Protocol Violations
+--------------------------------------------------------------
+
+* Notice of Disconnect not implemented.
+
+* Referal error not returned when base Dn of operation is a
+ referal.
+
+* LDAP URLs are not supported with the '%' escape syntax of
+ RFC 1738.
+
+* Control criticality is not checked on unrecognized controls.
+
+
Added: incubator/directory/eve/branches/start/build.xml
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/build.xml Thu Jun 24 00:06:35 2004
@@ -0,0 +1,759 @@
+<?xml version="1.0"?>
+<project name="eve" default="sars" basedir=".">
+
+ <!-- ============================================================
+ PROPERTY SETUP
+ ============================================================= -->
+
+ <!-- load properties files -->
+ <property file="${user.home}/build.properties"/>
+ <property file="${user.home}/.ant.properties"/>
+ <property file="${basedir}/ant.properties"/>
+ <property file="${basedir}/../ant.properties"/>
+ <property file="${basedir}/default.properties"/>
+ <property file="${basedir}/../default.properties"/>
+ <property file="${basedir}/../cocoon.properties"/>
+
+ <!-- Set the properties for intermediate directory -->
+ <property name="build.dir" value="build"/>
+ <property name="build.lib" value="${build.dir}/lib"/>
+ <property name="build.xdoclet" value="${build.dir}/xdoclet"/>
+ <property name="build.src" value="${build.dir}/src"/>
+ <property name="build.classes" value="${build.dir}/classes"/>
+ <property name="build.javadocs" value="${build.dir}/javadocs"/>
+ <property name="build.docs" value="${build.dir}/docs"/>
+ <property name="build.context" value="${build.dir}/documentation"/>
+ <property name="build.xdocs" value="${build.context}/content/xdocs"/>
+
+ <!-- Set the properties for source directories -->
+ <property name="src.dir" value="src"/>
+ <property name="java.dir" value="${src.dir}/java"/>
+ <property name="manifest.dir" value="${src.dir}/manifest"/>
+ <property name="conf.dir" value="${src.dir}/conf"/>
+ <property name="xdocs.dir" value="${src.dir}/xdocs"/>
+ <property name="dist.base" value="distributions"/>
+ <property name="remote.repo" value="http://cvs.apache.org/repository"/>
+
+ <property environment="env"/>
+
+ <!-- ============================================================
+ DEPENDENCY JARS PROPERTY SETUP
+ ============================================================= -->
+
+ <property
+ name="ldap-common.jar"
+ value="ldap-common-SNAPSHOT.jar"/>
+
+ <property
+ name="commons-collections.jar"
+ value="commons-collections-2.1.jar"/>
+
+ <property
+ name="commons-lang.jar"
+ value="commons-lang-2.0.jar"/>
+
+ <property
+ name="snacc.jar"
+ value="snacc-2.3.jar"/>
+
+ <property
+ name="antlr.jar"
+ value="antlr-2.7.2.jar"/>
+
+ <property
+ name="avalon-framework-api.jar"
+ value="avalon-framework-api-4.1.5.jar"/>
+
+ <property
+ name="avalon-framework-impl.jar"
+ value="avalon-framework-impl-4.1.5.jar"/>
+
+ <property
+ name="regexp.jar"
+ value="regexp-1.2.jar"/>
+
+ <property
+ name="ldap-snacc-provider.jar"
+ value="ldap-snacc-provider-SNAPSHOT.jar"/>
+
+ <property
+ name="oro.jar"
+ value="oro-2.0.7.jar"/>
+
+ <property
+ name="cornerstone-threads-api.jar"
+ value="cornerstone-threads-api-2.0.jar" />
+
+ <property
+ name="cornerstone-threads-impl.jar"
+ value="cornerstone-threads-impl-2.0.jar" />
+
+ <property
+ name="excalibur-thread.jar"
+ value="excalibur-thread-1.1.1.jar"/>
+
+ <property
+ name="jdbm.jar"
+ value="jdbm-0.12.jar"/>
+
+ <property
+ name="logkit.jar"
+ value="logkit-1.2.jar"/>
+
+ <!-- ============================================================
+ TOOLS JARS PROPERTY SETUP
+ ============================================================= -->
+
+ <property
+ name="xdoclet.jar"
+ value="xdoclet-20020825.jar"/>
+
+ <property
+ name="xjavadoc.jar"
+ value="xjavadoc-20020825.jar"/>
+
+ <property
+ name="phoenix-client.jar"
+ value="avalon-phoenix-client-4.0.4.jar"/>
+
+ <property
+ name="commons-logging.jar"
+ value="commons-logging-1.0.3.jar"/>
+
+ <property
+ name="log4j.jar"
+ value="log4j-1.2.7.jar"/>
+
+ <property
+ name="velocity.jar"
+ value="velocity-1.3.jar"/>
+
+ <property
+ name="jdom.jar"
+ value="jdom-b7.jar"/>
+
+ <!-- ============================================================
+ CLASSPATH SETUP
+ ============================================================= -->
+
+ <!-- Set some class paths -->
+ <path id="project.class.path">
+ <pathelement path="${java.class.path}"/>
+ <pathelement path="${build.classes}"/>
+ <pathelement path="${build.lib}/${ldap-common.jar}"/>
+ <pathelement path="${build.lib}/${commons-lang.jar}"/>
+ <pathelement path="${build.lib}/${snacc.jar}"/>
+ <pathelement path="${build.lib}/${antlr.jar}"/>
+ <pathelement path="${build.lib}/${avalon-framework-api.jar}"/>
+ <pathelement path="${build.lib}/${avalon-framework-impl.jar}"/>
+ <pathelement path="${build.lib}/${commons-collections.jar}"/>
+ <pathelement path="${build.lib}/${regexp.jar}"/>
+ <pathelement path="${build.lib}/${oro.jar}"/>
+ <pathelement path="${build.lib}/${cornerstone-threads-api.jar}"/>
+ <pathelement path="${build.lib}/${cornerstone-threads-impl.jar}"/>
+ <pathelement path="${build.lib}/${phoenix-client.jar}"/>
+ <pathelement path="${build.lib}/${excalibur-thread.jar}"/>
+ <pathelement path="${build.lib}/${jdbm.jar}"/>
+ <pathelement path="${build.lib}/${logkit.jar}"/>
+ </path>
+
+ <path id="tools.class.path">
+ <path refid="project.class.path"/>
+ <pathelement location="${build.lib}/${log4j.jar}"/>
+ <pathelement location="${build.lib}/${commons-logging.jar}"/>
+ <pathelement location="${build.lib}/${xdoclet.jar}"/>
+ <pathelement location="${build.lib}/${xjavadoc.jar}"/>
+ <pathelement location="${build.lib}/${phoenix-client.jar}"/>
+ <pathelement location="${build.lib}/${velocity.jar}"/>
+ <pathelement location="${build.lib}/${jdom.jar}"/>
+ </path>
+
+
+ <target name="get-deps">
+ <mkdir dir="${build.lib}"/>
+
+ <!-- ======================================================================
+ GET TOOL DEPENDENCY JARS
+ ======================================================================= -->
+
+ <get
+ usetimestamp="true"
+ src="${remote.repo}/log4j/jars/${log4j.jar}"
+ dest="${build.lib}/${log4j.jar}"
+ verbose="true"
+ />
+ <get
+ usetimestamp="true"
+ src="${remote.repo}/commons-logging/jars/${commons-logging.jar}"
+ dest="${build.lib}/${commons-logging.jar}"
+ verbose="true"
+ />
+ <get
+ usetimestamp="true"
+ src="${remote.repo}/xdoclet/jars/${xdoclet.jar}"
+ dest="${build.lib}/${xdoclet.jar}"
+ verbose="true"
+ />
+ <get
+ usetimestamp="true"
+ src="${remote.repo}/xjavadoc/jars/${xjavadoc.jar}"
+ dest="${build.lib}/${xjavadoc.jar}"
+ verbose="true"
+ />
+ <get
+ usetimestamp="true"
+ src="${remote.repo}/avalon-phoenix/jars/${phoenix-client.jar}"
+ dest="${build.lib}/${phoenix-client.jar}"
+ verbose="true"
+ />
+ <get
+ usetimestamp="true"
+ src="${remote.repo}/velocity/jars/${velocity.jar}"
+ dest="${build.lib}/${velocity.jar}"
+ verbose="true"
+ />
+ <get
+ usetimestamp="true"
+ src="${remote.repo}/jdom/jars/${jdom.jar}"
+ dest="${build.lib}/${jdom.jar}"
+ verbose="true"
+ />
+
+ <!-- ======================================================================
+ GET DEPENDENCY JARS
+ ======================================================================= -->
+
+ <get verbose="true" usetimestamp="true"
+ src="${remote.repo}/incubator-directory/jars/${ldap-common.jar}"
+ dest="${build.lib}/${ldap-common.jar}"
+ />
+
+ <get verbose="true" usetimestamp="true"
+ src="${remote.repo}/incubator-directory/jars/${ldap-snacc-provider.jar}"
+ dest="${build.lib}/${ldap-snacc-provider.jar}"
+ />
+
+ <get verbose="true" usetimestamp="true"
+ src="${remote.repo}/commons-lang/jars/${commons-lang.jar}"
+ dest="${build.lib}/${commons-lang.jar}"
+ />
+
+ <get verbose="true" usetimestamp="true"
+ src="http://ldapd.sourceforge.net/maven/repository/snacc4j/jars/${snacc.jar}"
+ dest="${build.lib}/${snacc.jar}"
+ />
+
+ <get verbose="true" usetimestamp="true"
+ src="${remote.repo}/antlr/jars/${antlr.jar}"
+ dest="${build.lib}/${antlr.jar}"
+ />
+
+ <get verbose="true" usetimestamp="true"
+ src="${remote.repo}/avalon-framework/jars/${avalon-framework-api.jar}"
+ dest="${build.lib}/${avalon-framework-api.jar}"
+ />
+
+ <get verbose="true" usetimestamp="true"
+ src="${remote.repo}/avalon-framework/jars/${avalon-framework-impl.jar}"
+ dest="${build.lib}/${avalon-framework-impl.jar}"
+ />
+
+ <get verbose="true" usetimestamp="true"
+ src="${remote.repo}/commons-collections/jars/${commons-collections.jar}"
+ dest="${build.lib}/${commons-collections.jar}"
+ />
+
+ <get verbose="true" usetimestamp="true"
+ src="${remote.repo}/regexp/jars/${regexp.jar}"
+ dest="${build.lib}/${regexp.jar}"
+ />
+
+ <get verbose="true" usetimestamp="true"
+ src="${remote.repo}/oro/jars/${oro.jar}"
+ dest="${build.lib}/${oro.jar}"
+ />
+
+ <get verbose="true" usetimestamp="true"
+ src="${remote.repo}/cornerstone-threads/jars/${cornerstone-threads-api.jar}"
+ dest="${build.lib}/${cornerstone-threads-api.jar}"
+ />
+
+ <get verbose="true" usetimestamp="true"
+ src="${remote.repo}/cornerstone-threads/jars/${cornerstone-threads-impl.jar}"
+ dest="${build.lib}/${cornerstone-threads-impl.jar}"
+ />
+
+ <get verbose="true" usetimestamp="true"
+ src="${remote.repo}/excalibur-thread/jars/${excalibur-thread.jar}"
+ dest="${build.lib}/${excalibur-thread.jar}"
+ />
+
+ <get verbose="true" usetimestamp="true"
+ src="${remote.repo}/jdbm/jars/${jdbm.jar}"
+ dest="${build.lib}/${jdbm.jar}"
+ />
+
+ <get verbose="true" usetimestamp="true"
+ src="${remote.repo}/logkit/jars/${logkit.jar}"
+ dest="${build.lib}/${logkit.jar}"
+ />
+ </target>
+
+ <!-- ======================================================
+
+
+ T A R G E T S
+
+
+ ======================================================= -->
+
+
+ <!-- ======================================================
+ C O M P I L A T I O N
+ ======================================================= -->
+
+
+ <target name="grammars" depends="get-deps">
+ <antlr target="src/antlr/schema.g"
+ outputdirectory="src/java/org/apache/eve/schema">
+ <classpath refid="tools.class.path"/>
+ </antlr>
+ </target>
+
+
+ <target name="compile" depends="grammars">
+ <mkdir dir="${build.classes}"/>
+
+ <javac srcdir="${java.dir}"
+ destdir="${build.classes}"
+ debug="${build.debug}"
+ optimize="${build.optimize}"
+ deprecation="${build.deprecation}">
+ <classpath refid="project.class.path"/>
+ </javac>
+
+ <copy todir="${build.classes}">
+ <fileset dir="${java.dir}">
+ <exclude name="**/test/**"/>
+ <exclude name="**/*.java"/>
+ </fileset>
+ </copy>
+ </target>
+
+
+ <!-- ======================================================
+ X I N F O A N D M A N I F E S T G E N E R A T I O N
+ ======================================================= -->
+
+ <target name="test-xdoclet">
+ <available classname="xdoclet.XDocletMain"
+ classpathref="tools.class.path"
+ property="xdoclet.present"/>
+ </target>
+
+ <target name="phoenix-xdoclet" depends="compile" ><!--if="xdoclet.present"-->
+ <mkdir dir="${build.xdoclet}"/>
+ <taskdef
+ name="phoenix-blocks"
+ classname="org.apache.avalon.phoenix.tools.xdoclet.PhoenixXDoclet"
+ classpathref="tools.class.path"/>
+
+ <phoenix-blocks destdir="${build.xdoclet}">
+ <fileset dir="${java.dir}">
+ <include name="org/apache/eve/event/protocol/*.java"/>
+ </fileset>
+ <blockinfo/>
+ <mxinfo/>
+ </phoenix-blocks>
+
+ <phoenix-blocks destdir="${build.xdoclet}">
+ <fileset dir="${java.dir}">
+ <include name="org/apache/eve/jndi/*.java"/>
+ </fileset>
+ <blockinfo/>
+ <mxinfo/>
+ </phoenix-blocks>
+
+ <phoenix-blocks destdir="${build.xdoclet}">
+ <fileset dir="${java.dir}">
+ <include name="org/apache/eve/input/*.java"/>
+ </fileset>
+ <blockinfo/>
+ <mxinfo/>
+ </phoenix-blocks>
+
+ <phoenix-blocks destdir="${build.xdoclet}">
+ <fileset dir="${java.dir}">
+ <include name="org/apache/eve/output/*.java"/>
+ </fileset>
+ <blockinfo/>
+ <mxinfo/>
+ </phoenix-blocks>
+
+ <phoenix-blocks destdir="${build.xdoclet}">
+ <fileset dir="${java.dir}">
+ <include name="org/apache/eve/encoder/*.java"/>
+ </fileset>
+ <blockinfo/>
+ <mxinfo/>
+ </phoenix-blocks>
+
+ <phoenix-blocks destdir="${build.xdoclet}">
+ <fileset dir="${java.dir}">
+ <include name="org/apache/eve/security/auth/*.java"/>
+ </fileset>
+ <blockinfo/>
+ <mxinfo/>
+ </phoenix-blocks>
+
+ <phoenix-blocks destdir="${build.xdoclet}">
+ <fileset dir="${java.dir}">
+ <include name="org/apache/eve/protocol/*.java"/>
+ </fileset>
+ <blockinfo/>
+ <mxinfo/>
+ </phoenix-blocks>
+
+ <phoenix-blocks destdir="${build.xdoclet}">
+ <fileset dir="${java.dir}">
+ <include name="org/apache/eve/decoder/*.java"/>
+ </fileset>
+ <blockinfo/>
+ <mxinfo/>
+ </phoenix-blocks>
+
+ <phoenix-blocks destdir="${build.xdoclet}">
+ <fileset dir="${java.dir}">
+ <include name="org/apache/eve/client/*.java"/>
+ </fileset>
+ <blockinfo/>
+ <mxinfo/>
+ </phoenix-blocks>
+
+ <phoenix-blocks destdir="${build.xdoclet}">
+ <fileset dir="${java.dir}">
+ <include name="org/apache/eve/schema/*.java"/>
+ </fileset>
+ <blockinfo/>
+ <mxinfo/>
+ </phoenix-blocks>
+
+ <phoenix-blocks destdir="${build.xdoclet}">
+ <fileset dir="${java.dir}">
+ <include name="org/apache/eve/listener/*.java"/>
+ </fileset>
+ <blockinfo/>
+ <mxinfo/>
+ </phoenix-blocks>
+
+ <phoenix-blocks destdir="${build.xdoclet}">
+ <fileset dir="${java.dir}">
+ <include name="org/apache/eve/backend/*.java"/>
+ </fileset>
+ <blockinfo/>
+ <mxinfo/>
+ </phoenix-blocks>
+
+ <phoenix-blocks destdir="${build.xdoclet}">
+ <fileset dir="${java.dir}">
+ <include name="org/apache/eve/backend/jdbm/*.java"/>
+ </fileset>
+ <blockinfo/>
+ <mxinfo/>
+ </phoenix-blocks>
+ </target>
+
+
+ <!-- Make .xinfo and manifest automatically for blocks -->
+ <target name="no-phoenix-xdoclet" depends="compile" unless="xdoclet.present">
+ <mkdir dir="${build.xdoclet}"/>
+ <unzip src="${src.dir}/generated-by-xdoclet.zip" dest="${build.xdoclet}"/>
+ </target>
+
+ <!-- ======================================================
+ P R O J E C T J A R S
+ ======================================================= -->
+
+ <target name="jars" depends="phoenix-xdoclet">
+ <!--depends="test-xdoclet, phoenix-xdoclet, no-phoenix-xdoclet"-->
+ <mkdir dir="${build.lib}"/>
+
+ <!-- Just jars the individual block packages not the required set of classes
+ the core classes need to be jared into a separate core.jar.
+ -->
+
+ <jar jarfile="${build.lib}/core.jar" basedir="${build.classes}">
+ <!-- Include entire package -->
+ <include name="org/apache/eve/**"/>
+
+ <!-- Exclude the blocks jared below -->
+ <exclude name="org/apache/eve/input/*"/>
+ <exclude name="org/apache/eve/output/*"/>
+ <exclude name="org/apache/eve/encoder/*"/>
+ <exclude name="org/apache/eve/event/protocol/*"/>
+ <exclude name="org/apache/eve/security/auth/*"/>
+ <exclude name="org/apache/eve/protocol/*"/>
+ <exclude name="org/apache/eve/decoder/*"/>
+ <exclude name="org/apache/eve/client/*"/>
+ <exclude name="org/apache/eve/schema/*"/>
+ <exclude name="org/apache/eve/listener/*"/>
+ <exclude name="org/apache/eve/backend/*"/>
+ </jar>
+
+ <jar jarfile="${build.lib}/event.jar" basedir="${build.classes}">
+ <include name="org/apache/eve/event/protocol/*"/>
+ <fileset dir="${build.xdoclet}">
+ <include name="org/apache/eve/event/protocol/*.xinfo"/>
+ <include name="org/apache/eve/event/protocol/*.mxinfo"/>
+ </fileset>
+ </jar>
+
+ <jar jarfile="${build.lib}/jndi.jar" basedir="${build.classes}">
+ <include name="org/apache/eve/jndi/*"/>
+ <fileset dir="${build.xdoclet}">
+ <include name="org/apache/eve/jndi/*.xinfo"/>
+ <include name="org/apache/eve/jndi/*.mxinfo"/>
+ </fileset>
+ </jar>
+
+ <jar jarfile="${build.lib}/input.jar" basedir="${build.classes}">
+ <include name="org/apache/eve/input/*"/>
+ <fileset dir="${build.xdoclet}">
+ <include name="org/apache/eve/input/*.xinfo"/>
+ <include name="org/apache/eve/input/*.mxinfo"/>
+ </fileset>
+ </jar>
+
+ <jar jarfile="${build.lib}/output.jar" basedir="${build.classes}">
+ <include name="org/apache/eve/output/*"/>
+ <fileset dir="${build.xdoclet}">
+ <include name="org/apache/eve/output/*.xinfo"/>
+ <include name="org/apache/eve/output/*.mxinfo"/>
+ </fileset>
+ </jar>
+
+ <jar jarfile="${build.lib}/encoder.jar" basedir="${build.classes}">
+ <include name="org/apache/eve/encoder/*"/>
+ <fileset dir="${build.xdoclet}">
+ <include name="org/apache/eve/encoder/*.xinfo"/>
+ <include name="org/apache/eve/encoder/*.mxinfo"/>
+ </fileset>
+ </jar>
+
+ <jar jarfile="${build.lib}/authman.jar" basedir="${build.classes}">
+ <include name="org/apache/eve/security/auth/*"/>
+ <fileset dir="${build.xdoclet}">
+ <include name="org/apache/eve/security/auth/*.xinfo"/>
+ <include name="org/apache/eve/security/auth/*.mxinfo"/>
+ </fileset>
+ </jar>
+
+ <jar jarfile="${build.lib}/protocol.jar" basedir="${build.classes}">
+ <include name="org/apache/eve/protocol/*"/>
+ <fileset dir="${build.xdoclet}">
+ <include name="org/apache/eve/protocol/*.xinfo"/>
+ <include name="org/apache/eve/protocol/*.mxinfo"/>
+ </fileset>
+ </jar>
+
+ <jar jarfile="${build.lib}/decoder.jar" basedir="${build.classes}">
+ <include name="org/apache/eve/decoder/*"/>
+ <fileset dir="${build.xdoclet}">
+ <include name="org/apache/eve/decoder/*.xinfo"/>
+ <include name="org/apache/eve/decoder/*.mxinfo"/>
+ </fileset>
+ </jar>
+
+ <jar jarfile="${build.lib}/client.jar" basedir="${build.classes}">
+ <include name="org/apache/eve/client/*"/>
+ <fileset dir="${build.xdoclet}">
+ <include name="org/apache/eve/client/*.xinfo"/>
+ <include name="org/apache/eve/client/*.mxinfo"/>
+ </fileset>
+ </jar>
+
+ <jar jarfile="${build.lib}/listener.jar" basedir="${build.classes}">
+ <include name="org/apache/eve/listener/*"/>
+ <fileset dir="${build.xdoclet}">
+ <include name="org/apache/eve/listener/*.xinfo"/>
+ <include name="org/apache/eve/listener/*.mxinfo"/>
+ </fileset>
+ </jar>
+
+ <jar jarfile="${build.lib}/schema.jar" basedir="${build.classes}">
+ <include name="org/apache/eve/schema/*"/>
+ <fileset dir="${build.xdoclet}">
+ <include name="org/apache/eve/schema/*.xinfo"/>
+ <include name="org/apache/eve/schema/*.mxinfo"/>
+ </fileset>
+ </jar>
+
+ <jar jarfile="${build.lib}/backend.jar" basedir="${build.classes}">
+ <include name="org/apache/eve/backend/*"/>
+ <fileset dir="${build.xdoclet}">
+ <include name="org/apache/eve/backend/*.xinfo"/>
+ <include name="org/apache/eve/backend/*.mxinfo"/>
+ </fileset>
+ </jar>
+
+ <jar jarfile="${build.lib}/backjdbm.jar" basedir="${build.classes}">
+ <include name="org/apache/eve/backend/jdbm/**"/>
+ <fileset dir="${build.xdoclet}">
+ <include name="org/apache/eve/backend/jdbm/*.xinfo"/>
+ <include name="org/apache/eve/backend/jdbm/*.mxinfo"/>
+ </fileset>
+ </jar>
+ </target>
+
+
+ <!-- ======================================================
+ C O R E T A R G E T S
+ ======================================================= -->
+
+ <target name="sars" depends="jars">
+ <taskdef name="sar" classname="org.apache.avalon.phoenix.tools.tasks.Sar">
+ <classpath refid="tools.class.path"/>
+ </taskdef>
+
+ <taskdef name="anakia" classname="org.apache.velocity.anakia.AnakiaTask">
+ <classpath refid="tools.class.path"/>
+ </taskdef>
+
+ <sar sarfile="${build.lib}/eve.sar"
+ config="${conf.dir}/config.xml"
+ environment="${conf.dir}/environment.xml"
+ assembly="${conf.dir}/assembly.xml">
+
+ <lib dir="src">
+ <include name="schema/**.schema"/>
+ </lib>
+
+ <lib dir="${build.lib}/">
+ <include name="${antlr.jar}"/>
+ <include name="authman.jar"/>
+ <include name="${avalon-framework-api.jar}"/>
+ <include name="${avalon-framework-impl.jar}"/>
+ <include name="${phoenix-client.jar}"/>
+ <include name="backend.jar"/>
+ <include name="backjdbm.jar"/>
+ <include name="client.jar"/>
+ <include name="${commons-collections.jar}"/>
+ <include name="${commons-lang.jar}"/>
+ <include name="${commons-logging.jar}"/>
+ <include name="core.jar"/>
+ <include name="${cornerstone-threads-api.jar}"/>
+ <include name="${cornerstone-threads-impl.jar}"/>
+ <include name="decoder.jar"/>
+ <include name="encoder.jar"/>
+ <include name="event.jar"/>
+ <include name="${excalibur-thread.jar}"/>
+ <include name="input.jar"/>
+ <include name="${jdbm.jar}"/>
+ <include name="jndi.jar"/>
+ <include name="${ldap-common.jar}"/>
+ <include name="${ldap-snacc-provider.jar}"/>
+ <include name="listener.jar"/>
+ <include name="${logkit.jar}"/>
+ <include name="${oro.jar}"/>
+ <include name="output.jar"/>
+ <include name="protocol.jar"/>
+ <include name="${regexp.jar}"/>
+ <include name="schema.jar"/>
+ <include name="${snacc.jar}"/>
+ </lib>
+ </sar>
+
+ <mkdir dir="dist"/>
+ <copy todir="dist">
+ <fileset dir="${build.lib}">
+ <include name="*.sar"/>
+ </fileset>
+ </copy>
+
+ <echo message="done with sars"/>
+ </target>
+
+
+ <!-- ======================================================
+ I N S T A L L D E P L O Y
+ ======================================================= -->
+
+ <target name="findInstallDir" unless="${install.dir}">
+ <property name="phoenix.home" value="${env.PHOENIX_HOME}"/>
+ <condition property="install.dir" value="${env.PHOENIX_HOME}/apps">
+ <not>
+ <contains string="${phoenix.home}" substring="env.PHOENIX_HOME"/>
+ </not>
+ </condition>
+ </target>
+
+ <target name="doPhoenixInstall"
+ unless="install.dir" depends="findInstallDir" >
+
+ <echo message="PHOENIX_HOME NOT SET!"/>
+ <echo message="CANNOT FIND PHOENIX INSTALLATION!"/>
+ <input
+ message="Would you like to download and install Phoenix into ./dist?"
+ validargs="yes,no"
+ addproperty="install.phoenix"/>
+ </target>
+
+ <target name="installPhoenix" depends="doPhoenixInstall" if="install.phoenix">
+ <get
+ usetimestamp="true" verbose="true"
+ src="${remote.repo}/avalon-phoenix/distributions/phoenix-4.0.4-bin.zip"
+ dest="${dist.dir}/phoenix-4.0.4-bin.zip"/>
+ <unzip src="${dist.dir}/phoenix-4.0.4-bin.zip" dest="${dist.dir}" />
+ <property name="install.dir" value="${dist.dir}/phoenix-4.0.4/apps"/>
+
+ <echo message="+--------------------------------------------------------"/>
+ <echo message=": Set the environment property PHOENIX_HOME: i.e"/>
+ <echo message=": PHOENIX_HOME=${dist.dir}/phoenix-4.0.4"/>
+ <echo message=": export PHOENIX_HOME"/>
+ <echo message=":"/>
+ <echo message=": Start the server using shell scripts or bat files:"/>
+ <echo message=": ${dist.dir}/phoenix-4.0.4/bin/phoenix.sh start"/>
+ <echo message=":"/>
+ <echo message=": NOTE: On UNIX you'll need to chmod +x the shell scripts"/>
+ <echo message="+--------------------------------------------------------"/>
+ </target>
+
+ <target name="install" depends="sars,installPhoenix"
+ description="Installs into Phoenix">
+
+ <echo message="Removing older installation if any from ${install.dir}"/>
+ <delete file="${install.dir}/eve.sar"/>
+ <delete dir="${install.dir}/eve/"/>
+
+ <!-- delete older conflicting thread pool jar -->
+ <delete file="${dist.dir}/phoenix-4.0.4/lib/excalibur-thread-1.1.jar"/>
+
+ <echo message="Installing to ${install.dir}"/>
+ <copy todir="${install.dir}">
+ <fileset dir="${build.lib}">
+ <include name="eve.sar"/>
+ </fileset>
+ </copy>
+ </target>
+
+ <target name="uninstall" depends="findInstallDir"
+ description="Uninstalls from Phoenix">
+ <delete dir="${install.dir}/eve/"/>
+ <delete file="eve.sar" dir="${install.dir}"/>
+ </target>
+
+ <target name="clean" description="Cleans up artifacts from build process">
+ <delete dir="${build.dir}"/>
+ <delete dir="${dist.dir}"/>
+ <delete dir="target"/>
+ <delete dir="test"/>
+ <delete>
+ <fileset dir="." includes="**/*~" defaultexcludes="no"/>
+ </delete>
+ <delete>
+ <fileset dir="src/java/org/apache/eve/schema"
+ includes="antlr*.*" defaultexcludes="no"/>
+ </delete>
+ </target>
+
+</project>
Added: incubator/directory/eve/branches/start/default.properties
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/default.properties Thu Jun 24 00:06:35 2004
@@ -0,0 +1,104 @@
+# ============================================================================
+# Standard Build Properties for Eve
+# ============================================================================
+# Specifies the default values for properties commonly required in ant build
+# scripts. Normally parts are overridden by ./{projectname}/default.properties
+# and/or ant.properties files. This file is not ment for editing by the
+# average user; use ant.properties files instead
+#
+#
+#
+#
+
+# ----------------------------------------------------------------------------
+# DOC GENERATION CONFIGURATION
+# ----------------------------------------------------------------------------
+# this should be overridden for each application
+
+name = eve-server
+Name = Eve Directory Server Project
+dir-name = eve-server
+version = 0.01
+package-version = 0.01
+year = 2002-2003
+
+# ----------------------------------------------------------------------------
+# COMPILATION ENVIRONMENT
+# ----------------------------------------------------------------------------
+# Settings used to configure compile environment
+
+build.debug = on
+build.optimize = off
+build.deprecation = off
+build.compress = false
+junit.failonerror = false
+
+# ----------------------------------------------------------------------------
+# DIRECTORY LOCATIONS
+# ----------------------------------------------------------------------------
+
+# ----- build destinations -----
+build.dir = ${basedir}/build
+build.classes = ${build.dir}/classes
+build.lib = ${build.dir}/lib
+build.conf = ${build.dir}/conf
+build.xdoclet = ${build.dir}/xdoclet
+build.testsrc = ${build.dir}/testsrc
+build.testclasses = ${build.dir}/testclasses
+build.xdocs = ${build.context}/content/xdocs
+build.docs = ${build.dir}/docs
+build.javadocs = ${build.docs}/api
+build.tests = ${build.dir}/tests
+build.reports = ${build.dir}/reports
+# intermediate location for documentation generation
+build.context = ${build.dir}/documentation
+
+# ----- build sources -----
+src.dir = ${basedir}/src
+java.dir = ${src.dir}/java
+conf.dir = ${src.dir}/conf
+test.dir = ${src.dir}/test
+manifest.dir = ${src.dir}/manifest
+xdocs.dir = ${src.dir}/xdocs
+lib.dir = ${basedir}/lib
+
+# ----- build distributions -----
+dist.dir = ${basedir}/dist
+dist.javadocs = ${dist.dir}/docs/api
+site.dir = ${basedir}/website/build/docs/apps/
+# directory for distribution archives
+dist.base = ${basedir}/distributions
+
+# ----------------------------------------------------------------------------
+# LIBRARY LOCATIONS
+# ----------------------------------------------------------------------------
+
+
+# ----------------------------------------------------------------------------
+# REMOTE DOCUMENTATION LOCATIONS
+# ----------------------------------------------------------------------------
+# Base pointers for non-xdocs documentation. Override these in .ant.properties
+# to link to local docs
+
+avalon.base = http://jakarta.apache.org/avalon
+framework.base = http://jakarta.apache.org/avalon/framework
+excalibur.base = http://jakarta.apache.org/avalon/excalibur
+phoenix.base = http://jakarta.apache.org/avalon/phoenix
+cornerstone.base = http://jakarta.apache.org/avalon/cornerstone
+logkit.base = http://jakarta.apache.org/avalon/logkit
+apps.base = http://jakarta.apache.org/avalon/apps
+testlet.base = http://jakarta.apache.org/avalon/testlet
+
+# ----------------------------------------------------------------------------
+# OTHER PROPERTIES
+# ----------------------------------------------------------------------------
+
+# name of .zip/.tar.gz/.bz2 files and their top-level directory
+dist.name = ${name}-${version}
+
+# name of jar file
+jar.name = ${name}-${version}.jar
+
+# which method of documetation generation to use
+documentation.tool = cocoon
+
Added: incubator/directory/eve/branches/start/docs/issues/normalization.txt
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/docs/issues/normalization.txt Thu Jun 24 00:06:35 2004
@@ -0,0 +1,89 @@
+
+Problem Description:
+
+Right now normalizers are run against attribute values without considering
+some of the pathalogical forms that can be present within the value. Schemas
+expose normalizers directly to external modules enabling them to perform
+normalization on values directly with the normalizer. This is common in
+backends that maintain their own indices or other parts of the system that
+need a cannonical representation for an attribute value.
+
+For example an attribute with a IA5CaseIgnoreMatch matching rule cannot
+normalize regions where literal quotes are used. Meaning it cannot lowercase
+the literal sections or deep trim spaces from it. It must be matched against
+as-is even though the matching rule states otherwise. Hence a user must put
+together filter attribute values in the same case and spacing with quotes to
+match against a literal section. In conclusion literal value sections override matching rules.
+
+Presently cannonical representations are normalized even in literal sections
+for attribute values. The DnParser on the otherhand correctly normalizes or
+defers normalization based on context perserving literal sections. Indices
+on DN attributes in this respect will be inconsistent when quotes are used
+and some searches will return more results than they should have.
+
+This potential problem is rare, depends on the data values used and requires
+the use of quotes. It is important yet not a show stopper, but should be
+solved eventually for the sake of correctness.
+
+
+Solution:
+
+We need to parse the value and apply the normalization function associated
+with the matching rule to non-literal sections only, concatenate normalized
+regions with literal regions and return this as the overall normalized value.
+
+So if we had an attribute 'abcxyz' where the matching rule is
+IA5CaseIgnoreMatch with the following value with boundry ticks:
+
+ 1 2 3 4 5 6
+ | | | | | |
+ 'cdJFAsdf \"Jack in The box\" j AS 2345DS'
+
+would be transformed into:
+
+ 1 2 3 4 5 6
+ | | | | | |
+ 'cdjfAsdf \"Jack in The box\" j as 2345ds'
+
+Here segments 12 and 56 are normalized using the matching rules assigned
+normalization funtion. Segment 34 is untouched as a literal. The
+transformed string is then used as an index key to lookup entries with
+this value.
+
+
+Implementation:
+
+Currently a value parser is used to correctly parse out a the values of
+DN name components optionally normalizing the values of RDN attributes
+based on their matching rules as specified by the schema manager. This
+parser is on in a two part parser system which together implement a
+parser with two lexical states using a token stream switcher. Complicating
+it further with code to merely parse a single attributes value would
+present a maintenence nightmare. Since these parsers are antlr generated
+we can easily create a new parser which would be very simple to parse just
+attribute values which normalizing them according their matching rules
+defined in a schema.
+
+Constructing a new parser adds an extra overhead. First of all a parser
+stores state and so must be synchronized upon. This creates contention.
+Secondly new string objects are instantiated all over the place presenting
+a potential performance problem. Indices manage value normalization to
+conduct searches so they can cache the most recently transformed values
+to prevent redundant normalizations accross subsystem boundries. The same
+value may be normalized several times if it is not cached. Also any such
+cache must be specific to an attribute to prevent value collisions in the
+cache. Indices are the best place for caching normalized values namely
+since the see the resultant products of normalization. Normalizers may
+only be seeing parts of value. In the example above a Normalizer never
+sees the complete input: it sees segments 12 and 56 without seeing segment
+34 at all. It would store two entries total for this attribute value pair.
+The cache in an index would store one entry who's key is the original
+value and the value is the normalized value. This is more efficient and
+practical.
+
+Indices must then manage a cache of normalized values and use them on
+cache hits or delegate normalization requests to the schema. The schema
+invokes a value parser with the correct normalizer for the attribute's
+matching rule and returns the resultant normalized value. This normalized
+value is also known as the cannonical value or simply the index key.
+
Added: incubator/directory/eve/branches/start/maven.xml
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/maven.xml Thu Jun 24 00:06:35 2004
@@ -0,0 +1,32 @@
+<project default="java:compile"
+ xmlns:j="jelly:core"
+ xmlns:u="jelly:util"
+ xmlns:ant="jelly:ant"
+ xmlns:maven="jelly:maven"
+ xmlns:m="maven"
+ xmlns:deploy="deploy">
+
+ <preGoal name="site">
+ <attainGoal name="docbook:transform"/>
+ </preGoal>
+
+ <postGoal name="site">
+ <attainGoal name="server:copy-images"/>
+ </postGoal>
+
+ <goal name="server:copy-images">
+ <copy toDir="target/docs/images">
+ <fileSet dir="${basedir}/src/images">
+ <include name="*.gif"/>
+ </fileSet>
+ </copy>
+ </goal>
+
+ <postGoal name="antlr:generate">
+ <copy
+ file="target/antlr/org/apache/eve/schema/antlrSchemaTokenTypes.txt"
+ toDir="target/classes/org/apache/eve/schema"
+ />
+ </postGoal>
+
+</project>
Added: incubator/directory/eve/branches/start/project.properties
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/project.properties Thu Jun 24 00:06:35 2004
@@ -0,0 +1,16 @@
+maven.ui.banner.background=#fff
+maven.ui.source.background=#fff
+maven.ui.section.background=#6a82b6
+maven.xdoc.date=left
+maven.xdoc.version=0.7.1
+
+# Override the Modules path in build.properties
+# This defines the directory under which all of
+# the module site content will be stored.
+module.name=ldapd-server
+maven.repo.remote=http://www.ibiblio.org/maven/,http://ldapd.sourceforge.net/maven/repository/,http://cvs.apache.org/repository
+
+# antlr configuration
+maven.antlr.grammars=schema.g
+maven.antlr.src.dir=src/antlr
+
Added: incubator/directory/eve/branches/start/project.xml
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/project.xml Thu Jun 24 00:06:35 2004
@@ -0,0 +1,227 @@
+<?xml version="1.0"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="maven-project.xsd">
+
+ <pomVersion>3</pomVersion>
+ <groupId>incubator-directory</groupId>
+ <id>eve-server</id>
+ <name>${module.name}</name>
+ <currentVersion>SNAPSHOT</currentVersion>
+
+ <developers>
+ <developer>
+ <name>Alex Karasulu</name>
+ <id>akarasulu</id>
+ <email>akarasulu at users.sourceforge.net</email>
+ <roles>
+ <role>PM</role>
+ <role>Founder</role>
+ <role>Developer</role>
+ <role>Architect</role>
+ <role>Lead Developer</role>
+ </roles>
+ </developer>
+
+ <developer>
+ <name>Robb Penoyer</name>
+ <id>rpenoyer</id>
+ <email>rpenoyer at users.sourceforge.net</email>
+ <roles>
+ <role>Developer</role>
+ </roles>
+ </developer>
+
+ <developer>
+ <name>Jim Bearce</name>
+ <id>bearcej</id>
+ <email>bearcej at users.sourceforge.net</email>
+ <roles>
+ <role>Project Manager</role>
+ <role>Developer</role>
+ </roles>
+ </developer>
+
+ <developer>
+ <name>Jeff Machols</name>
+ <id>jmachols</id>
+ <email>jmachols at users.sourceforget.net</email>
+ <roles>
+ <role>Developer</role>
+ </roles>
+ </developer>
+
+ <developer>
+ <name>Wes McKean</name>
+ <id>wesmckean</id>
+ <email>wesmckean at users.sourceforget.net</email>
+ <roles>
+ <role>Developer</role>
+ </roles>
+ </developer>
+
+ <developer>
+ <name>Peter Donald</name>
+ <id>donaldp</id>
+ <email>donaldp at users.sourceforge.net</email>
+ <roles>
+ <role>Advisor</role>
+ <role>Mentor</role>
+ <role>Consultant</role>
+ </roles>
+ </developer>
+
+ <developer>
+ <name>Noel Bergman</name>
+ <id>noeljb</id>
+ <email>noeljb at users.sourceforge.net</email>
+ <roles>
+ <role>Advisor</role>
+ <role>Mentor</role>
+ <role>Consultant</role>
+ </roles>
+ </developer>
+ </developers>
+
+ <dependencies>
+ <!-- Do we need all these dependencies?
+ log4j-core.jar
+ xdoclet-20020825.jar
+ xjavadoc-20020825.jar
+ -->
+
+ <dependency>
+ <groupId>logkit</groupId>
+ <artifactId>logkit</artifactId>
+ <version>1.2</version>
+ </dependency>
+
+ <dependency>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging</artifactId>
+ <version>1.0.2</version>
+ <url>http://jakarta.apache.org/commons/logging.html</url>
+ </dependency>
+
+ <dependency>
+ <groupId>commons-lang</groupId>
+ <artifactId>commons-lang</artifactId>
+ <version>2.0</version>
+ <url>http://jakarta.apache.org/commons/lang</url>
+ </dependency>
+
+ <dependency>
+ <groupId>oro</groupId>
+ <artifactId>oro</artifactId>
+ <version>2.0.7</version>
+ <url>http://jakarta.apache.org/oro/index.html</url>
+ </dependency>
+
+ <dependency>
+ <groupId>jdbm</groupId>
+ <artifactId>jdbm</artifactId>
+ <version>0.12</version>
+ </dependency>
+
+ <dependency>
+ <groupId>cornerstone-threads</groupId>
+ <artifactId>cornerstone-threads-impl</artifactId>
+ <version>2.0</version>
+ <url>http://avalon.apache.org/cornerstone/</url>
+ </dependency>
+
+ <dependency>
+ <groupId>cornerstone-threads</groupId>
+ <artifactId>cornerstone-threads-api</artifactId>
+ <version>2.0</version>
+ <url>http://avalon.apache.org/cornerstone/</url>
+ </dependency>
+
+ <dependency>
+ <groupId>excalibur-thread</groupId>
+ <artifactId>excalibur-thread</artifactId>
+ <version>1.1.1</version>
+ <url>http://avalon.apache.org/excalibur/thread/index.html</url>
+ </dependency>
+
+ <dependency>
+ <groupId>avalon-phoenix</groupId>
+ <artifactId>avalon-phoenix-client</artifactId>
+ <version>4.0</version>
+ <url>http://avalon.apache.org/phoenix/</url>
+ </dependency>
+
+ <dependency>
+ <groupId>incubator-directory</groupId>
+ <artifactId>ldap-common</artifactId>
+ <version>SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>incubator-directory</groupId>
+ <artifactId>ldap-snacc-provider</artifactId>
+ <version>SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>commons-collections</groupId>
+ <artifactId>commons-collections</artifactId>
+ <version>2.1</version>
+ <url>http://jakarta.apache.org/commons/collections.html</url>
+ </dependency>
+
+ <dependency>
+ <groupId>regexp</groupId>
+ <artifactId>regexp</artifactId>
+ <version>1.2</version>
+ <url>http://jakarta.apache.org/regexp/index.html</url>
+ </dependency>
+
+ <dependency>
+ <groupId>antlr</groupId>
+ <artifactId>antlr</artifactId>
+ <version>2.7.2</version>
+ <url>http://antlr.org/</url>
+ </dependency>
+
+ <dependency>
+ <groupId>avalon-framework</groupId>
+ <artifactId>avalon-framework-api</artifactId>
+ <version>SNAPSHOT</version>
+ <url>http://avalon.apache.org/framework/</url>
+ </dependency>
+
+ <dependency>
+ <groupId>avalon-framework</groupId>
+ <artifactId>avalon-framework-impl</artifactId>
+ <version>SNAPSHOT</version>
+ <url>http://avalon.apache.org/framework/</url>
+ </dependency>
+
+ </dependencies>
+
+
+ <build>
+ <nagEmailAddress>directory-dev@incubator.apache.org</nagEmailAddress>
+ <sourceDirectory>${basedir}/src/java</sourceDirectory>
+ <sourceModifications/>
+ <unitTestSourceDirectory/>
+ <integrationUnitTestSourceDirectory/>
+ <aspectSourceDirectory/>
+ <unitTest/>
+ </build>
+
+ <reports>
+ <report>maven-changelog-plugin</report>
+ <report>maven-developer-activity-plugin</report>
+ <report>maven-file-activity-plugin</report>
+ <report>maven-javadoc-plugin</report>
+ <report>maven-changes-plugin</report>
+ <report>maven-checkstyle-plugin</report>
+ <report>maven-file-activity-plugin</report>
+ <report>maven-javadoc-plugin</report>
+ <report>maven-jdepend-plugin</report>
+ <report>maven-jxr-plugin</report>
+ <report>maven-license-plugin</report>
+ <report>maven-tasklist-plugin</report>
+ </reports>
+</project>
Added: incubator/directory/eve/branches/start/sample.ant.properties
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/sample.ant.properties Thu Jun 24 00:06:35 2004
@@ -0,0 +1 @@
+maven.repo=C:/Documents and Settings/Administrator/.maven/repository
Added: incubator/directory/eve/branches/start/sample.build.properties
==============================================================================
Added: incubator/directory/eve/branches/start/src/antlr/schema.g
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/antlr/schema.g Thu Jun 24 00:06:35 2004
@@ -0,0 +1,309 @@
+header {
+ package org.apache.eve.schema;
+ import java.util.* ;
+}
+
+// ===================================================
+// TOKENS FOR LDAP SCHEMA SYNTAX LEXER DEFINITIONS
+//
+// -- (c) Apache Software Foundation --
+// -- Please refer to the LICENSE.txt file in the root directory of --
+// -- any directory project for copyright and distribution information. --
+//
+//
+// ===================================================
+
+
+class antlrSchemaSyntaxLexer extends Lexer ;
+
+options {
+ k = 4 ;
+ exportVocab=antlrSchema ;
+ charVocabulary = '\3'..'\377' ;
+ caseSensitive = false ;
+ testLiterals = false ;
+}
+
+
+//COMMENT : '#' (~'\n')* '\n'
+// ;
+
+WS : ( '#' (~'\n')* '\n' { newline(); }
+ | ' '
+ | '\t'
+ | '\r' '\n' { newline(); }
+ | '\n' { newline(); }
+ | '\r' { newline(); }
+ )
+ {$setType(Token.SKIP);} //ignore this token
+ ;
+
+OPEN_PAREN : '('
+ ;
+
+CLOSE_PAREN : ')'
+ ;
+
+OPEN_BRACKET : '{'
+ ;
+
+CLOSE_BRACKET : '}'
+ ;
+
+QUOTED_STRING : '\'' ( ~'\'' )* '\''
+ ;
+
+AND : '$'
+ ;
+
+OID :
+ ( '0'..'9' )+ ( '.' ( '0'..'9' )+ )*
+ ( OPEN_BRACKET ('0' .. '9')+ CLOSE_BRACKET )?
+ ;
+
+IDENTIFIER options { testLiterals=true; }
+ :
+ ( 'a' .. 'z') ( 'a' .. 'z' | '0' .. '9' | '-')*
+ ;
+
+
+class antlrSchemaParser extends Parser ;
+
+
+tokens {
+ ATTRIBUTE_TYPE = "attributetype" ;
+ NAME_KW = "NAME" ;
+ EQUALITY_KW = "EQUALITY" ;
+ ORDERING_KW = "ORDERING" ;
+ SYNTAX_KW = "SYNTAX" ;
+ SINGLEVAL_KW = "SINGLE-VALUE" ;
+ NOUSERMOD_KW = "NO-USER-MODIFICATION" ;
+ USAGE_KW = "USAGE" ;
+ DESC_KW = "DESC" ;
+ MAY_KW = "MAY" ;
+ MUST_KW = "MUST" ;
+ SUBSTR_KW = "SUBSTR" ;
+ SUP_KW = "SUP" ;
+ AUXILIARY_KW = "AUXILIARY" ;
+ STRUCTURAL_KW = "STRUCTURAL" ;
+ ABSTRACT_KW = "ABSTRACT" ;
+}
+
+
+schemafile [SchemaImpl a_schema]:
+{
+ AttributeSpec l_attribute = null ;
+ ObjectClassSpec l_objectClass = null ;
+}
+ ( l_attribute=attributedef
+ {
+ a_schema.addAttributeSpec(l_attribute) ;
+ }
+ |
+ l_objectClass=objectclassdef
+ {
+ a_schema.addObjectClassSpec(l_objectClass) ;
+ }
+ )+ EOF ;
+
+
+attributedef returns [AttributeSpec l_attribute]
+{
+ l_attribute = new AttributeSpec() ;
+ ArrayList l_nameList = null ;
+}
+ :
+ ATTRIBUTE_TYPE OPEN_PAREN oid:OID l_nameList=namelist
+ {
+ l_attribute.m_oid = oid.getText() ;
+ l_attribute.m_nameList = l_nameList ;
+ }
+ (
+ ( "DESC" desc:QUOTED_STRING
+ {
+ String quoted = desc.getText() ;
+ l_attribute.m_desc = quoted.substring(1, quoted.length() - 1) ;
+ }
+ ) |
+
+
+ ( "EQUALITY" equality:IDENTIFIER
+ {
+ l_attribute.m_equality = equality.getText().toLowerCase() ;
+ }
+ ) |
+
+
+ ( "SUBSTR" substr:IDENTIFIER
+ {
+ l_attribute.m_substr = substr.getText().toLowerCase() ;
+ }
+ ) |
+
+
+ ( "ORDERING" ordering:IDENTIFIER
+ {
+ l_attribute.m_ordering = ordering.getText().toLowerCase() ;
+ }
+ ) |
+
+
+ ( "SYNTAX" syntax:OID
+ {
+ l_attribute.m_syntax = syntax.getText() ;
+ }
+ ) |
+
+
+ ( "SINGLE-VALUE"
+ {
+ l_attribute.m_isSingleValue = true ;
+ }
+ ) |
+
+ ( "NO-USER-MODIFICATION"
+ {
+ l_attribute.m_canUserModify = false ;
+ }
+ ) |
+
+ ( "SUP" sup:IDENTIFIER
+ {
+ l_attribute.m_superClass = sup.getText().toLowerCase() ;
+ }
+ ) |
+
+
+ ( "USAGE" usage:IDENTIFIER
+ {
+ l_attribute.m_usage = usage.getText().toLowerCase() ;
+ }
+ )
+ )* CLOSE_PAREN ;
+
+
+objectclassdef returns [ObjectClassSpec l_objectClass]
+{
+ l_objectClass = new ObjectClassSpec() ;
+ ArrayList l_mayList = null ;
+ ArrayList l_mustList = null ;
+ ArrayList l_superClasses = null ;
+ ArrayList l_nameList = null ;
+
+}
+ :
+ "objectclass" OPEN_PAREN oid:OID l_nameList=namelist
+ {
+ l_objectClass.oid = oid.getText() ;
+ l_objectClass.nameList = l_nameList ;
+ }
+ (
+ ( "DESC" desc:QUOTED_STRING
+ {
+ String tmp = desc.getText() ;
+ l_objectClass.desc = tmp.substring(1, tmp.length() - 1) ;
+ }
+ ) |
+ ( l_superClasses=superclasslist
+ {
+ l_objectClass.superClasses = l_superClasses ;
+ }
+ ) |
+ ( "ABSTRACT"
+ { l_objectClass.type = ObjectClassSpec.ABSTRACT ; }
+ | "STRUCTURAL"
+ { l_objectClass.type = ObjectClassSpec.STRUCTURAL ; }
+ | "AUXILIARY"
+ { l_objectClass.type = ObjectClassSpec.AUXILIARY ; }
+
+ ) |
+ ( l_mustList=mustlist
+ {
+ l_objectClass.mustList = l_mustList ;
+ }
+ ) |
+ ( l_mayList=maylist
+ {
+ l_objectClass.mayList = l_mayList ;
+ }
+ )
+ )* CLOSE_PAREN ;
+
+
+superclasslist returns [ArrayList l_supList]
+{
+ l_supList = new ArrayList() ;
+}
+ :
+ "SUP" ( id:IDENTIFIER
+ {
+ l_supList.add(id.getText().toLowerCase()) ;
+ }
+
+ | OPEN_PAREN id2:IDENTIFIER
+ {
+ l_supList.add(id2.getText().toLowerCase()) ;
+ }
+
+ ( AND id3:IDENTIFIER
+
+ {
+ l_supList.add(id3.getText().toLowerCase()) ;
+ }
+
+ )* CLOSE_PAREN ) ;
+
+
+namelist returns [ArrayList l_nameList]
+{
+ l_nameList = new ArrayList() ;
+}
+ :
+ "NAME" ( name:QUOTED_STRING
+ {
+ String tmp = name.getText() ;
+ tmp = tmp.substring(1, tmp.length() - 1) ;
+ l_nameList.add(tmp) ;
+ }
+
+ | OPEN_PAREN (name2:QUOTED_STRING
+
+ {
+ String tmp = name2.getText() ;
+ tmp = tmp.substring(1, tmp.length() - 1) ;
+ l_nameList.add(tmp) ;
+ }
+
+ )+ CLOSE_PAREN ) ;
+
+
+
+maylist returns [ArrayList l_mayList]
+{
+ l_mayList = null ;
+}
+ : "MAY" ( IDENTIFIER | l_mayList=attributelist ) ;
+
+
+
+mustlist returns [ArrayList l_mustList]
+{
+ l_mustList = null ;
+}
+ :
+ "MUST" ( IDENTIFIER | l_mustList=attributelist ) ;
+
+
+attributelist returns [ArrayList l_list]
+{
+ l_list = new ArrayList() ;
+}
+ :
+ OPEN_PAREN id:IDENTIFIER
+ { l_list.add(id.getText().toLowerCase()) ; }
+ ( AND id2:IDENTIFIER { l_list.add(id2.getText().toLowerCase()) ; })*
+ CLOSE_PAREN ;
+
+
+
+
Added: incubator/directory/eve/branches/start/src/conf/assembly.xml
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/conf/assembly.xml Thu Jun 24 00:06:35 2004
@@ -0,0 +1,239 @@
+<?xml version="1.0"?>
+<!DOCTYPE assembly PUBLIC "-//PHOENIX/Assembly DTD Version 1.0//EN"
+ "http://jakarta.apache.org/avalon/dtds/phoenix/assembly_1_0.dtd">
+<assembly>
+
+ <!-- ======================================================================
+
+
+
+ C O R N E R S T O N E B L O C K S
+
+
+
+ ======================================================================= -->
+
+
+ <!-- ======================================================================
+ T H R E A D M A N A G E R B L O C K
+ ======================================================================= -->
+
+ <block
+ class="org.apache.avalon.cornerstone.blocks.threads.DefaultThreadManager"
+ name="thread-manager"/>
+
+
+
+ <!-- ======================================================================
+
+
+
+ S Y S T E M M O D U L E B L O C K S
+
+
+
+ ======================================================================= -->
+
+
+ <!-- ======================================================================
+ O U T P U T M O D U L E B L O C K
+ ======================================================================= -->
+
+ <block
+ class="org.apache.eve.output.OutputModule"
+ name="output">
+
+ <provide
+ name="thread-manager"
+ role="org.apache.avalon.cornerstone.services.threads.ThreadManager" />
+ </block>
+
+ <!-- ======================================================================
+ I N P U T M O D U L E B L O C K
+ ======================================================================= -->
+
+ <block
+ class="org.apache.eve.input.InputModule"
+ name="input">
+
+ <provide
+ name="decoder"
+ role="org.apache.eve.decoder.Decoder" />
+ <provide
+ name="thread-manager"
+ role="org.apache.avalon.cornerstone.services.threads.ThreadManager" />
+ </block>
+
+ <!-- ======================================================================
+ S C H E M A M O D U L E B L O C K
+ ======================================================================= -->
+
+ <block
+ class="org.apache.eve.schema.SchemaModule"
+ name="schema-manager"/>
+
+ <!-- ======================================================================
+ B A C K E N D N E X U S M O D U L E B L O C K
+ ======================================================================= -->
+
+ <block
+ class="org.apache.eve.backend.NexusModule"
+ name="nexus">
+ <provide
+ name="schema-manager"
+ role="org.apache.eve.schema.SchemaManager" />
+ </block>
+
+ <!-- ======================================================================
+ L I S T E N E R M O D U L E B L O C K
+ ======================================================================= -->
+
+ <block
+ class="org.apache.eve.listener.ListenerModule"
+ name="listener">
+ <provide
+ name="client"
+ role="org.apache.eve.client.ClientManager" />
+ </block>
+
+ <!-- ======================================================================
+ C L I E N T M O D U L E B L O C K
+ ======================================================================= -->
+
+ <block
+ class="org.apache.eve.client.ClientModule"
+ name="client">
+ <provide
+ name="decoder"
+ role="org.apache.eve.decoder.Decoder" />
+ <provide
+ name="input"
+ role="org.apache.eve.input.InputManager" />
+ <provide
+ name="output"
+ role="org.apache.eve.output.OutputManager" />
+ <provide
+ name="nexus"
+ role="org.apache.eve.backend.UnifiedBackend" />
+ <provide
+ name="protocol"
+ role="org.apache.eve.protocol.ProtocolEngine" />
+ <provide
+ name="thread-manager"
+ role="org.apache.avalon.cornerstone.services.threads.ThreadManager" />
+ </block>
+
+ <!-- ======================================================================
+ E N C O D E R M O D U L E B L O C K
+ ======================================================================= -->
+
+ <block
+ class="org.apache.eve.encoder.EncoderModule"
+ name="encoder">
+
+ <provide
+ name="output"
+ role="org.apache.eve.output.OutputManager" />
+ <provide
+ name="thread-manager"
+ role="org.apache.avalon.cornerstone.services.threads.ThreadManager" />
+ </block>
+
+ <!-- ======================================================================
+ D E C O D E R M O D U L E B L O C K
+ ======================================================================= -->
+
+ <block
+ class="org.apache.eve.decoder.DecoderModule"
+ name="decoder">
+ <provide
+ name="protocol"
+ role="org.apache.eve.protocol.ProtocolEngine" />
+ <provide
+ name="thread-manager"
+ role="org.apache.avalon.cornerstone.services.threads.ThreadManager" />
+ </block>
+
+ <!-- ======================================================================
+ P R O T O C O L M O D U L E B L O C K
+ ======================================================================= -->
+
+ <block
+ class="org.apache.eve.protocol.ProtocolModule"
+ name="protocol">
+
+ <provide
+ name="event"
+ role="org.apache.eve.event.protocol.EventManager" />
+
+ <provide
+ name="nexus"
+ role="org.apache.eve.backend.UnifiedBackend" />
+
+ <provide
+ name="authman"
+ role="org.apache.eve.security.auth.AuthenticationManager" />
+
+ <provide
+ name="encoder"
+ role="org.apache.eve.encoder.Encoder" />
+
+ <provide
+ name="output"
+ role="org.apache.eve.output.OutputManager" />
+
+ <provide
+ name="thread-manager"
+ role="org.apache.avalon.cornerstone.services.threads.ThreadManager" />
+ </block>
+
+ <!-- ======================================================================
+ J D B M B A C K E N D M O D U L E B L O C K
+ ======================================================================= -->
+
+ <block
+ class="org.apache.eve.backend.jdbm.JdbmModule"
+ name="backend0">
+ <provide
+ name="schema-manager"
+ role="org.apache.eve.schema.SchemaManager" />
+ <provide
+ name="nexus"
+ role="org.apache.eve.backend.UnifiedBackend" />
+ </block>
+
+ <!-- ======================================================================
+ A U T H E N T I C A T I O N M O D U L E B L O C K
+ ======================================================================= -->
+
+ <block
+ class="org.apache.eve.security.auth.AuthenticationModule"
+ name="authman">
+ <provide
+ name="nexus"
+ role="org.apache.eve.backend.UnifiedBackend" />
+ </block>
+
+
+ <!-- ======================================================================
+ J N D I P R O V I D E R M O D U L E B L O C K
+ ======================================================================= -->
+
+ <block
+ class="org.apache.eve.jndi.JndiProviderModule"
+ name="jndi">
+ <provide
+ name="nexus"
+ role="org.apache.eve.backend.UnifiedBackend" />
+ </block>
+
+ <!-- ======================================================================
+ E V E N T M A N A G E R M O D U L E B L O C K
+ ======================================================================= -->
+
+ <block
+ class="org.apache.eve.event.protocol.EventModule"
+ name="event">
+ </block>
+
+</assembly>
Added: incubator/directory/eve/branches/start/src/conf/config.xml
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/conf/config.xml Thu Jun 24 00:06:35 2004
@@ -0,0 +1,376 @@
+<config>
+
+ <!-- ======================================================================
+ T H R E A D M A N A G E R C O N F I G
+ ======================================================================= -->
+
+ <thread-manager>
+
+ <!-- Used by OutputManager for writing to client streams -->
+
+ <thread-group>
+ <name>output</name>
+ <priority>3</priority>
+ <is-daemon>false</is-daemon>
+ <max-threads>5</max-threads>
+ <min-threads>1</min-threads>
+ <min-spare-threads>3</min-spare-threads>
+ </thread-group>
+
+
+
+ <!-- Used by InputManager for monitoring client connections -->
+
+ <thread-group>
+ <name>client</name>
+ <priority>3</priority>
+ <is-daemon>false</is-daemon>
+ <max-threads>5</max-threads>
+ <min-threads>1</min-threads>
+ <min-spare-threads>3</min-spare-threads>
+ </thread-group>
+
+
+
+ <!-- Used by ClientManager Stage -->
+
+ <thread-group>
+ <name>clientstage</name>
+ <priority>3</priority>
+ <is-daemon>false</is-daemon>
+ <max-threads>5</max-threads>
+ <min-threads>1</min-threads>
+ <min-spare-threads>3</min-spare-threads>
+ </thread-group>
+
+
+
+ <!-- Used for the ProtocolEngine processors and should be at least
+ equal to the 'client' pool if not more -->
+
+ <thread-group>
+ <name>processor</name>
+ <priority>3</priority>
+ <is-daemon>false</is-daemon>
+ <max-threads>5</max-threads>
+ <min-threads>1</min-threads>
+ <min-spare-threads>3</min-spare-threads>
+ </thread-group>
+
+
+
+ <!-- Used for the Encoder and should be at least
+ equal to the 'client' pool if not more -->
+
+ <thread-group>
+ <name>encoder</name>
+ <priority>3</priority>
+ <is-daemon>false</is-daemon>
+ <max-threads>5</max-threads>
+ <min-threads>1</min-threads>
+ <min-spare-threads>3</min-spare-threads>
+ </thread-group>
+
+
+
+ <!-- Used for the Decoder and should be at least
+ equal to the 'client' pool if not more -->
+
+ <thread-group>
+ <name>decoder</name>
+ <priority>3</priority>
+ <is-daemon>false</is-daemon>
+ <max-threads>5</max-threads>
+ <min-threads>1</min-threads>
+ <min-spare-threads>3</min-spare-threads>
+ </thread-group>
+
+
+
+ <!-- Everything else -->
+ <thread-group>
+ <name>default</name>
+ <priority>2</priority>
+ <is-daemon>false</is-daemon>
+ <max-threads>4</max-threads>
+ <min-threads>1</min-threads>
+ <min-spare-threads>3</min-spare-threads>
+ </thread-group>
+ </thread-manager>
+
+
+ <!-- ======================================================================
+ S C H E M A C O N F I G
+ ======================================================================= -->
+
+ <schema-manager>
+ <!-- S T A G E : I -->
+ <!-- files are parsed first to build file schemas -->
+
+ <schema name="our"
+ filepath="schema/our.schema" />
+ <schema name="core"
+ filepath="schema/core.schema" />
+ <schema name="vendor"
+ filepath="schema/vendor.schema" />
+ <schema name="corba"
+ filepath="schema/corba.schema" />
+ <schema name="cosine"
+ filepath="schema/cosine.schema" />
+ <schema name="java"
+ filepath="schema/java.schema" />
+ <schema name="misc"
+ filepath="schema/misc.schema" />
+
+ <!--
+ <schema name="nis"
+ filepath="schema/nis.schema" />
+ <schema name="krb5-kdc"
+ filepath="schema/krb5-kdc.schema" />
+ -->
+ <schema name="inetorgperson"
+ filepath="schema/inetorgperson.schema" />
+
+ <!-- S T A G E : II -->
+ <!-- built-ins: deepTrimToLower, deepTrim, trim, dnNormalize, asis -->
+ <!-- regex version is perl5 -->
+
+ <normalization default="asis">
+ <normalizer op="deepTrimToLower" rule="caseIgnoreMatch"/>
+ <normalizer op="deepTrimToLower" rule="caseIgnoreListMatch"/>
+ <normalizer op="deepTrimToLower" rule="caseIgnoreIA5Match"/>
+ <normalizer op="deepTrimToLower" rule="objectidentifiermatch"/>
+ <normalizer op="deepTrim" rule="caseExactIA5Match"/>
+ <normalizer op="deepTrim" rule="telephoneNumberMatch"/>
+ <normalizer op="dnNormalize" rule="distinguishedNameMatch"/>
+
+ <normalizer rule="someNewBogusRule">
+ <regex value="s/abc/123/g"/>
+ <regex value="/ /d"/>
+ <regex value="y/def/DEF/"/>
+ </normalizer>
+ </normalization>
+
+ <!-- S T A G E : III -->
+ <!-- built-ins: accept, . . ., TBA -->
+ <!-- regex version is perl5 -->
+ <syntax-checkers default="accept">
+ <!-- fictitious: matches yes, Yes, YES etc -->
+ <syntax-checker oid="1.2.34.2.1.2.3.4523.1.56.4.2.34.5345.3">
+ <regex value="/yes/i"/>
+ </syntax-checker>
+ </syntax-checkers>
+
+ <!-- S T A G E : IV -->
+ <!-- Subschema Administrative Area Used by backend0 -->
+ <SAA dn="dc=example,dc=com">
+ <schema-ref schema="our"/>
+ <schema-ref schema="core"/>
+ <schema-ref schema="cosine"/>
+ <schema-ref schema="corba"/>
+ <schema-ref schema="java"/>
+ <schema-ref schema="misc"/>
+ <schema-ref schema="inetorgperson"/>
+ </SAA>
+ </schema-manager>
+
+
+ <!-- ======================================================================
+ A U T H E N T I C A T I O N M A N A G E R C O N F I G
+ ======================================================================= -->
+
+ <authman>
+ </authman>
+
+
+ <!-- ======================================================================
+ U N I F I E D B A C K E N D N E X U S C O N F I G
+ ======================================================================= -->
+
+ <nexus>
+ <RootDSE>
+ <attribute name="namingContexts" value="dc=example,dc=com" />
+
+ <!-- Currently in this config there is no replica
+ The examples below are of alternative server's that contain
+ the same naming contexts that this server contains.
+
+ <attribute name="altServer" value="ldap://replica1:389" />
+ <attribute name="altServer" value="ldap://replica2:389" />
+ -->
+
+ <!-- Currently there are no supported extended ops
+ The extention below is RefreshRequest protocol operation defined as an
+ extention for dynamic directories see http://www.ietf.org/rfc/rfc2589.txt
+ for more information.
+
+ <attribute name="supportedExtension" value="1.3.6.1.4.1.1466.101.119.1" />
+ -->
+
+ <!-- Currently there are no supported control ops
+ These below are VLV (Virtual List View) controls and the
+ LDAP Control for a Duplicate Entry Representation of Search Results
+
+ <attribute name="supportedControl" value="2.16.840.1.113730.3.4.9" />
+ <attribute name="supportedControl" value="2.16.840.1.113730.3.4.10" />
+ <attribute name="supportedControl" value="2.16.840.1.113719.1.27.101.1" />
+ <attribute name="supportedControl" value="2.16.840.1.113719.1.27.101.2" />
+ <attribute name="supportedControl" value="2.16.840.1.113719.1.27.101.3" />
+ -->
+
+ <!-- Currently SASL is not implemented yet.
+ The following URL explains more about the SASL mechanisms used:
+ http://www.ietf.org/rfc/rfc2829.txt
+
+ <attribute name="supportedSASLMechanisms"
+ value="ANONYMOUS PLAIN OTP DIGEST-MD5 CRAM-MD5" />
+ -->
+
+ <attribute name="subschemaSubentry" value="cn=subschema" />
+ <attribute name="supportedLDAPVersion" value="3" />
+ <attribute name="vendorName" value="ASF" />
+ <attribute name="vendorVersion" value="eve-0.01" />
+ </RootDSE>
+ </nexus>
+
+
+ <!-- ======================================================================
+ I N P U T M O D U L E C O N F I G
+ ======================================================================= -->
+
+ <output>
+ <stage name="output" poolname="output">
+ </stage>
+ </output>
+
+
+ <!-- ======================================================================
+ I N P U T M O D U L E C O N F I G
+ ======================================================================= -->
+
+ <input>
+ </input>
+
+
+ <!-- ======================================================================
+ D E C O D E R C O N F I G
+ ======================================================================= -->
+
+ <decoder>
+ <stage name="decoder" poolname="decoder">
+ </stage>
+ </decoder>
+
+
+ <!-- ======================================================================
+ E N C O D E R C O N F I G
+ ======================================================================= -->
+
+ <encoder>
+ <stage name="encoder" poolname="encoder">
+ </stage>
+ </encoder>
+
+
+ <!-- ======================================================================
+ P R O T O C O L E N G I N E C O N F I G
+ ======================================================================= -->
+
+ <protocol>
+ <stage name="protocol" poolname="processor">
+ </stage>
+ </protocol>
+
+
+ <!-- ======================================================================
+ S E R V E R L I S T E N E R C O N F I G
+ ======================================================================= -->
+
+
+ <listener>
+ <port>1396</port>
+ <host>localhost</host>
+ <backlog>50</backlog>
+ </listener>
+
+ <!--
+ <listener>
+ <port>1396</port>
+ <host>172.18.9.200</host>
+ <backlog>50</backlog>
+ </listener>
+ -->
+
+
+ <!-- ======================================================================
+ C L I E N T M A N A G E R S T A G E C O N F I G
+ ======================================================================= -->
+
+ <client>
+ <stage name="client" poolname="clientstage">
+ </stage>
+ </client>
+
+
+ <!-- ======================================================================
+ J D B M B A C K E N D ( 0 ) C O N F I G
+ ======================================================================= -->
+
+ <backend0>
+ <!-- Backend configuration properties -->
+
+
+ <!-- ==================================================================
+ Suffix Entry Definition:
+
+ The suffix entry is automatically created for the first time
+ when the backend is brought up and it is not found. If it
+ already exists then this section is used simply to get the
+ Dn to the backend.
+
+ =================================================================== -->
+
+ <suffix>
+ <attribute name="distinguishedname" value="dc=example,dc=com" />
+ <attribute name="objectclass" value="top" />
+ <attribute name="objectclass" value="domain" />
+ <attribute name="dc" value="example" />
+ </suffix>
+
+ <adminUserDN>cn=admin,dc=example,dc=com</adminUserDN>
+ <adminUserPassword>jPasswordField1</adminUserPassword>
+ <workingDirPath>var/backend0</workingDirPath>
+ <entryCacheSize>1000</entryCacheSize>
+
+ <!-- Specific To Jdbm DB Backend -->
+ <indices>
+ <index name="l"/>
+ <index name="ou"/>
+ <index name="cn"/>
+ <index name="sn"/>
+ <index name="dc"/>
+ <index name="uid"/>
+ <index name="mail"/>
+ <index name="givenName"/>
+ <index name="roomnumber"/>
+ <index name="objectclass"/>
+ </indices>
+ </backend0>
+
+
+ <!-- ======================================================================
+ J N D I P R O V I D E R M O D U L E C O N F I G
+ ======================================================================= -->
+
+ <jndi>
+ </jndi>
+
+
+ <!-- ======================================================================
+ E V E N T M O D U L E C O N F I G
+ ======================================================================= -->
+
+ <event>
+ </event>
+
+</config>
Added: incubator/directory/eve/branches/start/src/conf/environment.xml
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/conf/environment.xml Thu Jun 24 00:06:35 2004
@@ -0,0 +1,132 @@
+<?xml version="1.0"?>
+<!--
+ README!
+
+ Basic config file that sets up context for server application.
+
+
+-->
+
+<environment>
+ <logs>
+ <!--
+
+ L O G C A T E G O R I E S
+ ===========================
+
+ Note that a log <category> element's name attribute corresponds to the
+ name of the block in the assembly.xml file. Hence each block is a log
+ category in this configuration.
+
+ Also the target attribute of the <category> element is the name of the
+ <log-target> element's name attribute which determines where or rather
+ which log file we route the log event to.
+
+ -->
+
+ <category name=""
+ target="default"
+ priority="DEBUG"/>
+
+ <category name="jndi"
+ target="jndi"
+ priority="DEBUG"/>
+
+ <category
+ name="input"
+ target="io"
+ priority="DEBUG"/>
+
+ <category
+ name="output"
+ target="io"
+ priority="DEBUG"/>
+
+ <category
+ name="nexus"
+ target="backend-modules"
+ priority="DEBUG"/>
+
+ <category
+ name="backend0"
+ target="backend-modules"
+ priority="DEBUG"/>
+
+ <category
+ name="authman"
+ target="authentication"
+ priority="DEBUG"/>
+
+ <category
+ name="protocol"
+ target="protocol"
+ priority="DEBUG"/>
+
+ <category
+ name="listener"
+ target="listener"
+ priority="DEBUG"/>
+
+ <category
+ name="client"
+ target="listener"
+ priority="DEBUG"/>
+
+ <category
+ name="schema-manager"
+ target="schema"
+ priority="DEBUG"/>
+
+ <category
+ name="encoder"
+ target="asn1"
+ priority="DEBUG"/>
+
+ <category
+ name="decoder"
+ target="asn1"
+ priority="DEBUG"/>
+
+
+ <category name="event"
+ target="event"
+ priority="DEBUG"/>
+
+ <!-- Logfile for Event Manager -->
+ <log-target name="event" location="/logs/event.log"/>
+
+ <!-- Logfile for Input/Output Managers -->
+ <log-target name="io" location="/logs/io.log"/>
+
+ <!-- Logfile for ASN1 BER Encoding/Decoding -->
+ <log-target name="asn1" location="/logs/asn1.log"/>
+
+ <!-- Logfile for Server Side Jndi Provider -->
+ <log-target name="jndi" location="/logs/jndi.log"/>
+
+ <!-- Logfile for server listener -->
+ <log-target name="listener" location="/logs/listener.log"/>
+
+ <!-- Logfile for backends and the backend manager -->
+ <log-target name="backend-modules" location="/logs/backends.log"/>
+
+ <!-- Logfile for the authentication module -->
+ <log-target name="authentication" location="/logs/authentication.log"/>
+
+ <!-- Logfile for the protocol server module -->
+ <log-target name="protocol" location="/logs/protocol.log"/>
+
+ <!-- Default where everything else goes -->
+ <log-target name="default" location="/logs/misc.log"/>
+
+ <!-- Schema Manager Log File -->
+ <log-target name="schema" location="/logs/schema.log"/>
+ </logs>
+
+ <policy>
+ <grant code-base="sar:SAR-INF/lib/*">
+ <permission class="java.security.AllPermission"/>
+ </grant>
+ </policy>
+
+</environment>
Added: incubator/directory/eve/branches/start/src/docbook/design/authentication-module.xml
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/docbook/design/authentication-module.xml Thu Jun 24 00:06:35 2004
@@ -0,0 +1,86 @@
+<?xml version="1.0"?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD Simplified DocBook XML V4.1.2.5//EN"
+ "http://www.oasis-open.org/docbook/xml/simple/4.1.2.5/sdocbook.dtd">
+
+<article class="whitepaper">
+ <title>Module Implementation</title>
+
+ <articleinfo>
+ <author><othername>akarasulu</othername></author>
+ <editor><othername>$Author: bearcej $</othername></editor>
+ <revhistory>
+ <revision>
+ <revnumber>$Revision: 1.3 $</revnumber>
+ <date>$Date: 2003/05/03 01:21:32 $</date>
+ <revdescription>
+ <para>
+$Log: authentication-module.xml,v $
+Revision 1.3 2003/05/03 01:21:32 bearcej
+Remove tabs from doc files and fix linefeeds.
+
+Revision 1.2 2003/03/23 13:24:46 akarasulu
+Added these files from the ALPHA-0_7 branch.
+
+Revision 1.1.2.1 2003/03/10 23:24:19 akarasulu
+Moved design documentation from docs/design to src/docbook/design.
+
+Revision 1.1.2.1 2003/03/03 04:49:25 akarasulu
+Added as placeholders for now.
+
+ </para>
+ </revdescription>
+ </revision>
+ </revhistory>
+ </articleinfo>
+
+ <abstract>
+ <para>
+ </para>
+ </abstract>
+
+ <section>
+ <title>Document TODOs:</title>
+ <itemizedlist>
+ <listitem><para>
+ Add diagrams.
+ </para></listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Implementation</title>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+ </section>
+
+ <section>
+ <title>Future</title>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+ </section>
+
+ <section>
+ <title>Faults</title>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+ </section>
+
+</article>
Added: incubator/directory/eve/branches/start/src/docbook/design/backend-module.xml
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/docbook/design/backend-module.xml Thu Jun 24 00:06:35 2004
@@ -0,0 +1,490 @@
+<?xml version="1.0"?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD Simplified DocBook XML V4.1.2.5//EN"
+ "http://www.oasis-open.org/docbook/xml/simple/4.1.2.5/sdocbook.dtd">
+
+<article class="whitepaper">
+ <title>Module Implementation</title>
+
+ <articleinfo>
+ <author><othername>akarasulu</othername></author>
+ <editor><othername>$Author: bearcej $</othername></editor>
+ <revhistory>
+ <revision>
+ <revnumber>$Revision: 1.6 $</revnumber>
+ <date>$Date: 2003/05/03 01:43:08 $</date>
+ <revdescription>
+ <para>
+$Log: backend-module.xml,v $
+Revision 1.6 2003/05/03 01:43:08 bearcej
+Add maven file to help generate server site.
+Modify graphic links again.
+Remove tabs from doc files and fix linefeeds.
+
+Revision 1.5 2003/05/03 01:21:32 bearcej
+Remove tabs from doc files and fix linefeeds.
+
+Revision 1.4 2003/04/21 21:11:50 bearcej
+
+* Fix broken links in documentation.
+
+Revision 1.3 2003/04/08 02:29:55 bearcej
+* Clean up project.properties
+* Fix logos in project.xml
+* Fix links to image files in docs
+
+Revision 1.2 2003/03/23 13:24:46 akarasulu
+Added these files from the ALPHA-0_7 branch.
+
+Revision 1.1.2.5 2003/03/15 17:35:24 bearcej
+Fix href to BackendInterface.gif
+
+Revision 1.1.2.4 2003/03/15 17:07:26 bearcej
+Fix figure tags to conform to simple docbook (note: maven will not handle
+correctly without a maven patch)
+Modified Files:
+ Tag: ALPHA-0_7
+ backend-module.xml
+
+Revision 1.1.2.3 2003/03/12 02:11:56 akarasulu
+Checking partial backend module docs.
+
+Revision 1.1.2.2 2003/03/11 01:26:41 akarasulu
+Started up BackendModule documentation - more to come soon.
+
+Revision 1.1.2.1 2003/03/10 23:24:19 akarasulu
+Moved design documentation from docs/design to src/docbook/design.
+
+Revision 1.1.2.2 2003/03/10 23:12:06 akarasulu
+Moved these images to src/xdocs/design
+
+Revision 1.1.2.1 2003/03/03 04:49:25 akarasulu
+Added as placeholders for now.
+
+ </para>
+ </revdescription>
+ </revision>
+ </revhistory>
+ </articleinfo>
+
+ <abstract>
+ <para>
+ The BackendModule is an abstract base class which implements the
+ AtomicBackend service interface. The abstract module provides a
+ starting point for backend module developers. Backend modules are
+ the Directory Information Bases (DIB) which store entries served
+ by the directory. Several backends of various types may coexist
+ within the same directory under different naming contexts. The goal
+ of this document is to describe the server to backend contract
+ specified by interfaces within the org.apache.eve.backend package.
+ Special emphesis will be placed on the the AtomicBackend service
+ interface, as well as other helper interfaces and classes.
+ </para>
+ </abstract>
+
+ <section>
+ <title>Document TODOs:</title>
+ <itemizedlist>
+ <listitem><para>
+ Add diagrams.
+ </para></listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Architecture</title>
+
+ <para>
+ Backends relate one to one with naming contexts exposed by the
+ server. Backends are specialized databases customized for the
+ storage and retieval of entries participating within a DIB's
+ namespace. The LDAP access model and naming model are tightly
+ intertwined. The interfaces defining a backend module reflect
+ the tight coupling between these models. The operations against
+ backends fit into one of three categories: configuration parameter
+ methods, structural DIT management operations and nCRUD entry
+ life-cycle operations.
+ </para>
+
+ <para>
+ Backends require interfaces to Create, Read, Update and Delete
+ (CRUD) entries. These operations form the basis the CRUD life-cycle
+ model for in-memory objects repeatedly retrived from and stored
+ back to disk. For the purpose of this discussion, we refer to the
+ copy held on disk as the disk shadow copy. It shadows the in-memory
+ image rather than mirroring it, since at any instant in time the
+ in-memory image may not be the same as the shadowed image on disk.
+ Under such circumstances the in-memory image is considered dirty.
+ The process of applying the computations used to synchronize
+ in-memory images is called store optimization. Store optimization
+ reverts dirty entires to clean entries. Every backing store
+ confronts the task of store optimization at some point. A backend
+ module is no exception and the exact means used to acheive
+ synchronization is highly specific to the backing store
+ implementation. Regardless of the backend implementation, the
+ architecture strives to abstract away storage mechanisms to present
+ a common entry life-cycle facade. The use of the CRUD model
+ achives this goal by breaking down the life-cycle into small atomic
+ operations easily implemented by encapsulating specific data
+ storage mechanisms.
+ </para>
+
+ <para>
+ Under CRUD, the addition of an entry to a backend requires an
+ initial set of attributes, followed by a create operation. The
+ create operation arguments provide the initial attribute set
+ required to prevent a schema violation based on the entry's
+ objectclasses. The identifiers, values and number of attributes
+ composing the initial set vary with respect to the entry. If the
+ language supports variable argument lists, attribute ids and values
+ could be provided directly as create arguments. Better yet an
+ empty entry object without a respective shadow copy on disk, could
+ be instanciated and populated with attributes. The in-memory
+ entry object could then be used as the sole argument to a create
+ operation passing in all required attributes and their values in
+ one object. The latter approach leads to cleaner code and to a
+ slightly altered version of the CRUD model. Instantiation of the
+ in-memory entry shell, without a shadowed disk image, adds the
+ less central 'New' operation to CRUD. The addition of the 'New'
+ operation yeilds the modified CRUD or nCRUD model. The core Backend
+ super interface supports the nCRUD entry life-cycle model by
+ declaring the following methods:
+ </para>
+
+ <table id="tab1">
+ <title>Supported nCRUD Operations</title>
+ <tgroup cols="5">
+ <thead>
+ <row><entry>Method</entry>
+ <entry>CRUD Op</entry>
+ <entry>Source State</entry>
+ <entry>Target State</entry>
+ <entry>Description</entry></row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>newEntry(String a_dn):LdapEntry</entry>
+ <entry>New</entry>
+ <entry>NA</entry>
+ <entry>New</entry>
+ <entry>
+ Creates a new invalid LdapEntry object instance
+ only. Invalid entries are not shadowed in the
+ backing store, they are merely empty containers.
+ </entry>
+ </row>
+ <row>
+ <entry>create(LdapEntry a_entry):void</entry>
+ <entry>Create</entry>
+ <entry>New</entry>
+ <entry>Clean</entry>
+ <entry>
+ Clean entries are valid LdapEntry object
+ instances that are consistant with their mirror
+ image in the backing store.
+ </entry>
+ </row>
+ <row>
+ <entry>read(Name a_dn):LdapEntry</entry>
+ <entry>Read</entry>
+ <entry>NA</entry>
+ <entry>Clean</entry>
+ <entry>
+ Instantiates a valid LdapEntry instance to
+ mirror the copy held within the backing store.
+ </entry>
+ </row>
+ <row>
+ <entry>update(LdapEntry):void</entry>
+ <entry>Update</entry>
+ <entry>Dirty</entry>
+ <entry>Clean</entry>
+ <entry>
+ Updates the shadow copy in the backing store to
+ mirror the in memory LdapEntry image supplied.
+ </entry>
+ </row>
+ <row>
+ <entry>delete(LdapEntry):void</entry>
+ <entry>Delete</entry>
+ <entry>Clean|Dirty</entry>
+ <entry>Deleted</entry>
+ <entry>
+ Deletes the shadowed copy within the backing
+ store, and invalidates the LdapEntry argument.
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>
+ The Backend super interface declares the minimum set of operations
+ required to manage a DIB. These methods include the nCRUD
+ operations tabulated in Table I above. nCRUD operations model the
+ entry life-cycle causing transitions between entry states depicted
+ in Figure I below. The states are implied abstract nCRUD states.
+ They are not necessarily modeled explicity within any
+ implementation.
+ </para>
+
+ <figure id="fig1">
+ <title>CRUD Life-cycle States</title>
+ <graphic fileref="../images/CRUDLifecycle.gif"/>
+ </figure>
+
+ <para>
+ The Backend interface also declares DIB namespace management
+ operations. Namespace management operations affect the structure
+ of the DIB without adding or removing entries. Name modifications
+ upon entries occur to reflect namespace alterations. Entry
+ attributes other than those used for the relative distinguished
+ name (RDN) never change. Examples of such operations are move()
+ and modifyRdn(). Other Backend interface operations like search(),
+ getParent(), hasEntry() and listChildren(), do not fit into either
+ the nCRUD category nor do they fit into the catagory of namespace
+ operations. They are modified Read operations which enable specific
+ lookups and generalized mass Reads as DIB queries.
+ </para>
+
+ <para>
+ The Backend super interface is extended by two sub interfaces:
+ UnifiedBackend and AtomicBackend. Both are Avalon service
+ interfaces. <ulink url="http://avalon.apache.org/framework/">
+ Avalon Framework</ulink> defines the concept of a service as a
+ interface fulfilling a role within a system. The idea leads to
+ Service Oriented Programing (SOP), which breaks a system down into
+ a set of services. By convention Avalon, differentiates service
+ interfaces from ordinary interfaces based on the present of a ROLE
+ constant. The ROLE constant is a String set to the fully qualified
+ name of the service interface. An example of a service interface
+ is shown below:
+ </para>
+
+ <programlisting>
+ package com.calculator
+
+ interface CalculatorService
+ {
+ String ROLE = "com.calculator.CalculatorService" ;
+
+ int add(int a_arg1, int a_arg2) ;
+ int sub(int a_arg1, int a_arg2) ;
+ int div(int a_arg1, int a_arg2) ;
+ int mlt(int a_arg1, int a_arg2) ;
+ }
+ </programlisting>
+
+ <para>
+ The CalculatorService service interface exposes a set of arithmetic
+ operations accessible to other services within a system. Note the
+ ROLE constant which is set to the fully qualified name of the
+ interface. Unlike this example service interface the Backend
+ interface does not have a ROLE constant, hence it is not a service
+ interface. The Backend interface alone cannot be implemented by a
+ module within the server, instead one of its sub interfaces must be
+ implemented.
+ </para>
+
+ <para>
+ The AtomicBackend interface is a service interface according to the
+ Avalon definition with a ROLE constant set to the fully qualified
+ name of AtomicBackend: org.apache.eve.backend.AtomicBackend. All
+ backends
+
+ <footnote>
+ <para>
+ Until now we loosely referred to a naming context's DIB as
+ a backend and will continue to do so. For lack of a better
+ term, all AtomicBackend implementations are simply referred
+ to as backends in lowercase. When we specifically refer to
+ the Backend interface, the 'B' in Backend will be
+ capitalized and followed by the word 'interface'.
+ </para>
+ </footnote>
+
+ bound to an indivisible naming context implement the
+ AtomicBackend service interface. Indivisible implies that all
+ entries within the context's namespace are stored within a single
+ DIB: an implementation of AtomicBackend. The UnifiedBackend in
+ contrast unifies the namespaces of all AtomicBackends under one
+ composite Backend. The <ulink url="nexus-module.html">NexusModule
+ </ulink> documentation discusses the UnifiedBackend service
+ interface and its implementation in more detail.
+ </para>
+
+ <figure id="fig2">
+ <title>Figure II: Backend Interfaces</title>
+ <graphic fileref="../images/BackendInterfaces.gif"/>
+ </figure>
+
+ <para>
+ The interface heirarchy differentiates common DIB operations from
+ those that are specific to the UnifiedBackend and an AtomicBackend.
+ The Backend super interface contains methods common tto both
+ services. Inspection of <link linkend="fig2">Figure II.</link>
+ reviels the differentiating methods between the two service
+ interfaces which consequently defines their specific roles and their
+ behavoir. An AtomicBackend has a suffix, or naming context root
+ specified by a (non-empty string) LDAP distinguished name. The
+ UnifiedBackend does not. The UnifiedBackend cannot return a suffix
+ DN if it is composed of many naming contexts. Which context root
+ would it return? Furthurmore, it would be redundant to have a
+ getSuffix() method on the UnifiedBackend interface since the implied
+ suffix for the UnifiedBackend is the root of all roots: the empty
+ string DN. The AtomicBackend inherits method declarations from the
+ BackendConfig super interface through interface polymorphism and
+ UnifiedBackend does not. The BackendConfig interface defines
+ standard configuration parameters applicable only to backends that
+ directly store entries. Configuration parameters like isReadOnly()
+ does not make sense for a forwarding UnifiedBackend which delegates
+ entry and namespace operations to owning AtomicBackends. Nothing
+ makes the distinction more apparent than the methods exposed by the
+ UnifiedBackend which register, unregister, list, and return
+ AtomicBackends and the context's they are bound to.
+ </para>
+
+ <para>
+ The Backend interface is the common super interface for all
+ services providing DIB operations like nCRUD operations and
+ namespace operations. It's methods alone do not constitute a
+ service. Our intention was to allow for two drastically different
+ backend types while making their differences transparent through
+ the common Backend super interface. This way conversations between
+ each AtomicBackend and a caller can be routed by way of the
+ UnifiedBackend.
+ </para>
+
+ <para>
+ With the differences clearly outlined between the core backend
+ interfaces, let's consider their simularities and some of the
+ common helper classes involved. Close inspection reviels the
+ throws of NamingExceptions within virtually every core backend
+ interface. The throws directly reflect the close relationship
+ between the LDAP access model and the LDAP naming model. These
+ two aspects of LDAP are inseperable. All entries are named,
+ possesing a unique distinguished name as defined by X.500 and
+ LDAP. Even the call to instantiate a new entry object via newEntry
+ requires a distinguished name. Naming is inherent to LDAP and
+ cannot be abstracted away from an LDAP DIB. A name is required to
+ retrieve, change or store and search for an entry.
+ </para>
+
+ <para>
+ Up until now, most methods declared by the Backend interface have
+ been explained, yet some return types from those methods acting as
+ helper classes have not. Namely, mass read operations or searches
+ return a Cursor. Before looking at how we define a Cursor as part
+ of the server to backend contract lets consider the abstract notion
+ of a cursor. The concept obviously arose from a database server's
+ need to conserve resources. A database server may contain far more
+ data than can fit into physical memory, and must share whatever
+ memory resources it has across concurrent clients. Queries have the
+ potential to return a massive amount of data to the client. For
+ these reasons databases do not have the option of buffering query
+ results before transmission to the client. If they do it must be
+ at an extremely minimal level, or it must use seconday disk memory
+ to do so. Cursors are designed to return one search candidate at
+ a time streaming results back to the client.
+
+ require the concept of a cursor.
+ The potential of returning the contents of the entire directory
+ tree exists. All entries cannot possibly be loaded into memory to
+ be returned to the client at any one time with anything but trivial
+ databases. Cursors return values one at a time without requiring
+ the entire search set to be in memory at any one time.
+ </para>
+
+ <para>
+ BackendModule simply implements some Avalon life-cycle methods out of the box on
+ behalf of the developer trying to write a new type of backend. Our
+ architectural focus is not restricted to this class, however it's
+ value add will be discussed within the implementation section of
+ this document. For architectural and implementation specific
+ details regarding specific backend implementations available for the
+ LDAPd server please consult the backend specific documentation.
+ Below we list the various backends available, hyperlinked to their
+ documentation sets:
+ </para>
+
+ <itemizedlist>
+ <listitem><para>
+ <ulink url="/../../../backend-blank.html">JDBM Module
+ </ulink> - Default non-relational module using the
+ <ulink url="http://jdbm.sourceforge.net">JDBM BTree</ulink>
+ implementation. JDBM is a Java based UNIX DBM implementation.
+ </para></listitem>
+
+ <listitem><para>
+ <ulink url="/../../../backend-blank.html">Berkeley Module
+ </ulink> - Optional module using the
+ <ulink url="http://www.sleepycat.com">BerkeleyDB</ulink>
+ non-relational database. BerkeleyDB is a native C database that
+ uses an API to access BTree backed binary data.
+ </para></listitem>
+
+ <listitem><para>
+ <ulink url="/../../../module-blank.html">JDBC Module
+ </ulink> - Optional module using JDBC to store entries within a
+ relational database.
+ </para></listitem>
+ </itemizedlist>
+
+ <section>
+ <title>Entry CRUD Methods And DIB Operations</title>
+
+ <para>
+ The Backend interface specifies entry Create, Read, Update and
+ Delete (CRUD) operations and various DIB operations which don't
+ quite fit into a strictly CRUD model. Examples of such
+ operations would be move(), search() and listChildren(). The
+ Backend interface declares the minimum set of DIB operations
+ expected from a backend. Notice in <link linkend="fig1">Figure
+ I</link> that all Backend interface methods throw
+ NamingExceptions or one of its subtypes. The CRUD specific
+ operations are listed below in Table I and the corresponding
+ lifecycle state transitions are depicted in Figure II below it:
+ </para>
+
+ <para>
+ The CRUD
+ </para>
+ </section>
+ </section>
+
+ <section>
+ <title>Implementation</title>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+ </section>
+
+ <section>
+ <title>Future</title>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+ </section>
+
+ <section>
+ <title>Faults</title>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+ </section>
+
+</article>
Added: incubator/directory/eve/branches/start/src/docbook/design/client-module.xml
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/docbook/design/client-module.xml Thu Jun 24 00:06:35 2004
@@ -0,0 +1,496 @@
+<?xml version="1.0"?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD Simplified DocBook XML V4.1.2.5//EN"
+ "http://www.oasis-open.org/docbook/xml/simple/4.1.2.5/sdocbook.dtd">
+
+<article class="whitepaper">
+ <title>Client Module Implementation</title>
+
+ <articleinfo>
+ <author><othername>akarasulu</othername></author>
+ <editor><othername>$Author: bearcej $</othername></editor>
+ <revhistory>
+ <revision>
+ <revnumber>$Revision: 1.6 $</revnumber>
+ <date>$Date: 2003/05/03 01:21:32 $</date>
+ <revdescription>
+ <para>
+$Log: client-module.xml,v $
+Revision 1.6 2003/05/03 01:21:32 bearcej
+Remove tabs from doc files and fix linefeeds.
+
+Revision 1.5 2003/03/26 23:02:46 jmachols
+Added changes to ClientModule implementation to bring us towards a cleaner
+session and client manager.
+
+Revision 1.4 2003/03/26 22:48:54 akarasulu
+Factored some notes back into docs given to Jeff for changes to the Client
+Manager.
+
+Revision 1.3 2003/03/26 03:53:50 jmachols
+Documenting changes and future enhancements.
+
+Revision 1.2 2003/03/23 13:24:46 akarasulu
+Added these files from the ALPHA-0_7 branch.
+
+Revision 1.1.2.3 2003/03/15 17:38:49 bearcej
+cvs causing problems with xml processing
+
+Revision 1.1.2.2 2003/03/15 17:08:42 bearcej
+Add abstract tags around para for abstract description.
+Modified Files:
+ Tag: ALPHA-0_7
+ client-module.xml
+
+Revision 1.1.2.1 2003/03/10 23:24:19 akarasulu
+Moved design documentation from docs/design to src/docbook/design.
+
+Revision 1.1.2.2 2003/03/02 04:41:29 akarasulu
+*** empty log message ***
+
+Revision 1.1.2.1 2003/03/02 04:26:09 akarasulu
+ClientModule implementation document.
+
+ </para>
+ </revdescription>
+ </revision>
+ </revhistory>
+ </articleinfo>
+
+ <abstract>
+ <para>
+ The ClientManager service is implemented by the ClientModule. The
+ service is intended for client connection and hence session management.
+ Session management plays a critical role in managing controls, user
+ profiles, authorization and the tracking of session variables.
+ </para>
+ </abstract>
+
+ <section>
+ <title>Document TODOs:</title>
+ <itemizedlist>
+ <listitem><para>
+ Add sequence diagrams for the handler.
+ </para></listitem>
+
+ <listitem><para>
+ Add diagrams to show some of the design concepts hit below
+ like the use of the ClientKey as a primary key, the use of
+ a thread context to pass it around etc. Maybe a good sequence
+ diagram to show the steps to enable the storage of the ClientKey
+ within the thread context is worth while. Drive this stuff home
+ with some diagrams because its really dry reading at the moment.
+ It puts me to sleep and I wrote it.
+ </para></listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Design</title>
+
+ <para>
+ Stateful protocols like LDAP maintain a client socket connection
+ through out the duration of a "session". Several requests are
+ issued within the scope of a session. The socket connection
+ forms the basis to the concept of a client session. The socket
+ contains the IO streams and connection parameters which uniquely
+ identify the connection. These parameters are the client/server TCP
+ ports and the IP interfaces used to establish the connection.
+ Connection parameters alone do not encapsulate all the information
+ needed to complete the notion of an LDAP session. Protocol oriented
+ parameters specific to each client's session must be associated
+ with the connection. Such parameters include the identy of the
+ session owner, search controls and other operational modifiers. As
+ stated within the objectives of the LDAPd project, we intend to
+ provide the community with a rich LDAP application development
+ environment on par with modern RDBMSs. A session interface serves
+ as an exposed API, and it enables these goals by allowing user
+ defined session variables to be read and written. Our intent on
+ differentiating between application, session and request scope
+ parameters drives the design of the server and more specifically
+ the role of the ClientManager in session state management.
+ </para>
+
+ <para>
+ Several factors constrain our design. Among these factors are good
+ architectural principals. These constraints are itemized below:
+ </para>
+
+ <itemizedlist>
+ <listitem><para>
+ Maintain a separation of concerns (SOC) to minimize coupling
+ between subsystems. This can be achieved by centralizing client
+ management operations and isolating it within a single server
+ module if possible or within the subsystem package of the
+ module.
+ </para></listitem>
+
+ <listitem><para>
+ Recognize session management as a cross cutting aspect of any
+ stateful protocol server which counter acts SOC and increases
+ coupling. Use design patterns to balance the affects of this
+ pervasive aspect.
+ </para></listitem>
+
+ <listitem><para>
+ Use the Inversion of Control (IOC) design pattern to protect
+ sensitive resources while prividing access to privledged
+ components.
+ </para></listitem>
+
+ <listitem><para>
+ Balance these factors within a SEDA architecture with loosely
+ coupled events between stages.
+ </para></listitem>
+ </itemizedlist>
+
+ <para>
+ The role of the ClientManager service revolves around the management
+ of clients, their connections and their session parameters. Before
+ the introduction of core interfaces and classes used to establish
+ the subsystem facade, the notion of a client and session requires a
+ clear definition. To a stateful protocol server a client is a
+ connection. A process may posses multiple connections to the
+ server. Each connection regardless of the source is a client. So
+ whether connections are made locally, from other hosts, from the
+ same process on a single host, all are treated as separate clients.
+ Each connection maintains session state on the server. Session
+ state stores session specific variables that are not directly
+ related to defining or managing the connection. For example one
+ would not expect the identity of the authenticated user to be held
+ within a socket connection object. The session encapsulates both
+ the connection parameters and other indirectly related session
+ parameters. All fall under the umbrella of a client session and are
+ inseperable. The addition of a client implies the prior creation
+ of a connection and the subsequent establishment of a client
+ session. The drop of a client implies the close of a socket
+ connection and the destruction of the client's session.
+ Consequently, all outstanding requests dependent on it are destroyed
+ as well.
+ </para>
+
+ <para>
+ Design objectives revolve around the abstraction of the client and
+ the session. Several associations are loosely managed using a
+ unique primary key to identify a client. The final ClientKey class
+ defines the primary key. It distinctly identifies a client based
+ on an identifier string constructed from connection endpoint
+ parameters. Clients may form connections eminating from any host
+ IP interface through any authorized port on that interface. A
+ server host may have multiple IP interfaces and the server process
+ can chose to listen to any number of authorized TCP ports off those
+ interfaces. Hence a client socket connection on the client host
+ endpoint is defined by the IP interface and the TCP port used. The
+ client socket on the server side is defined by the server host's IP
+ interface and the TCP ports of the interface on which the connection
+ is established. Both sets of endpoint parameters are required to
+ form a unique key distinctly identifing the client. The primary key
+ identifier of the ClientKey is composed of these four parameters.
+ </para>
+
+ <para>
+ Sessions and connections can be bound together using the client PK
+ with associative tables or Maps. The ClientSession interface
+ defines the methods to be supported by a session entity.
+ ClientSession implementation instances are assocated one to one with
+ a ClientKey, and a client Socket. Depending on the object required
+ the key is used to access the respective Map to return the
+ associated client resouce.
+ </para>
+
+ <para>
+ The ClientKey is used as the handle on the client and its session.
+ From it, associated objects can be looked up using ClientManager
+ methods. Access to the key and to the ClientManager service are
+ sufficent to apply operations affecting the state of the client
+ within the server. For this reason every SEDA event except for the
+ ConnectEvent has a handle on the ClientKey object. The key is
+ passed along from stage to stage within the events. Stage modules
+ that require the need to access client session state or affect
+ changes to the client connection do so using this key and the
+ ClientManager service interfaces.
+ </para>
+
+ <para>
+ The ClientKey object is also critical for client IO synchronization
+ within and between stages. The OutputManager and the InputManager
+ implementations must make sure that only one LDAP PDU is being
+ recieved or delivered at one time. A PDU may however be sent while
+ one is being recieved. These requirements are accomplished by
+ synchronizing on the ClientKey lock objects used for input and
+ output synchronization.
+ </para>
+
+ <para>
+ The ClientKey nor the ClientSession or the ClientManager for that
+ matter, ever expose raw constructs used to manage the socket or IO
+ streams. Meaning the actual client socket or its IO streams are not
+ accessible via API calls. The encapsulation of the sockets and
+ its IO streams prevents tampering through public APIs. It also
+ makes it harder for other stages to access these streams to read
+ or write to the client. Services like the OuputManager and the
+ InputManager need eventually to write and read from these streams
+ Application of the Inversion of Control design pattern facilitates
+ this without compromizing these sensitive resouces. Both the
+ InputManager and the OutputManager expose interfaces to register and
+ unregister a client socket's input and output stream respectively.
+ The ClientManager is responsible for managing the [un]registration
+ process to enable and disable clients for IO within the server. In
+ this respect the ClientManager controls what resources are made
+ available to these IO managers. It does not expose accessor methods
+ to access these IO streams by ClientKey so that IO managers can look
+ them up. Doing so would publicly expose the streams to other
+ unauthorized components within the server thereby bypassing
+ encapsulation. By passing only a stream and not the socket the
+ ClientManager also prevents these IO services from interfering with
+ the physical socket connection. If sockets were passed rather than
+ IO streams connected to the socket then the socket can be closed
+ without proper cleanup. With separation of concern this is the
+ responsibility of the ClientManager service and not that of an
+ InputManager or an OutputManager. Streams passed to these IO
+ managers also need not be the socket streams. They can instead be
+ wrapper streams that do not close the underlying data stream when
+ close operations take place. Both managers together are responsible
+ for IO not the open or close of these connections. Giving them the
+ power to do so would violate several design principals. With IOC
+ the IO managers can only mess up what they are expected to do and
+ no more. Other parts of the server never see these conduits to the
+ client. Only controlled and privledged access to these streams from
+ IO managers are possible.
+ </para>
+
+ <para>
+ The ClientManager enables the addition of clients and the removal of
+ clients from the server using the add and drop service interfaces
+ methods. These methods are intended to setup or tear down IO stream
+ registrations and handle session object intialization as discussed.
+ The add method is called when a connection is initially established
+ even before a bind operation completes. The session in this case
+ has an LdapPrincipal with an empty yet valid Dn which connotates an
+ anonymous user. When binding anonymously the empty string Dn is
+ used. The drop method is intended to close a client's connection
+ and invalidate it's ClientSession object. The mappings used use to
+ track the Socket by ClientKey are removed and the ClientKey is
+ used to unregister the client's respective IO streams with both
+ IO manager modules. The ClientKey is also expired to prevent its
+ use for any outstanding requests left in the stage pipeline. Any
+ outstanding operations in progress or within the stage pipeline must
+ be terminated when the client is dropped: this is a requirement of
+ the protocol.
+ </para>
+
+ <para>
+ Some modules within the server are not stages so they do not recieve
+ events with payloads carrying ClientKeys. Access to the
+ ClientSession by way of ClientKey is only possible through method
+ call arguments. Between stages calls may be made by stage threads
+ to other simple modules which in turn call other simple modules.
+ The method call chain can be very long especially if recursion is
+ used. Having every simple module method pass in a ClientKey or
+ ClientSession argument is impractical. Just imagine to tunnel the
+ ClientSession down to one method it would have to be carried
+ through multiple stack frames regardless of whether it is used in
+ the intermediate method call or not. This would dramatically effect
+ readibility and confuse those trying to decipher the code.
+ </para>
+
+ <para>
+ The ClientManager service specifically confronts this issue which
+ has the possibility of arrising in every stage of processing. Two
+ interfaces are provided to associate and disassociate stage threads
+ with ClientKeys. The threadAssociate() method binds the ClientKey
+ to the context of the calling Thread. Subsequence calls to the no
+ argument getClientSession() method extracts the bound ClientKey
+ from the calling Thread's context to use in a lookup that returns
+ the associated ClientSession. This way stages can bind the
+ ClientKey of incomming events to the contexts of stage worker
+ Threads right before event processing. While stage Threads make
+ calls to other non-staged modules synchronously in the context of
+ the stage worker Thread, the ClientKey will always accompany the
+ method call. Simple modules use the no argument accessors to
+ extract the ClientSession associated with the call without having
+ to pass around ClientKeys or handles to the ClientSession. Once
+ the stage worker Thread completes event processing it disassociates
+ the ClientKey from its context via a call to threadDisassociate()
+ on the ClientManager. The facility is provided for all stages that
+ need to take advantage of this aspect of the service.
+ </para>
+
+ <para>
+ With all these modules having dependencies on the ClientManager
+ service cyclic dependencies between the ClientManager and other
+ modules are unavoidable. The ClientManager service in this sense
+ by far the most congested resource within the entire system.
+ Microkernel containers like Phoenix, will not allow cyclic
+ references between blocks or modules. To avoid these pitfalls down
+ the road precautions were taken to define new channels through which
+ references can be made across modules in a well defined and
+ constrained fashion without violating cyclic dependency rules within
+ an Avalon container. Avalon uses the service method and the
+ ServiceManager interface to facilitate the lifecycle stage where
+ services acquire handles to other services they depend upon. To
+ prevent the detection of true cyclic relationships between the the
+ ClientManager and other modules extra interfaces are defined. These
+ interfaces are intended to be implemented by modules that depend on
+ the ClientManager yet somewhere down the line the ClientManager
+ either directly or indirectly depends on them. So the goal is to
+ have these modules which would raise cyclic dependency errors in
+ Avalon containers obtain their backreference to the ClientManager
+ though a mechanism other than the regular Servicable life-cycle.
+ These modules should be clearly marked as imposing cyclic
+ dependencies by way of the ClientManager. Their access to the
+ ClientManager service handle also needs to be controlled by the
+ ClientManager through Inversion of Control. The ClientManager
+ chooses who speaks to it and acts in some respect like a master
+ module. The dependent modules act like slaves. The master slave
+ relationship becomes more apparent by investigating the
+ ClientManagerSlave interface required of all modules depending on
+ the ClientManager service. There is one method that needs to be
+ implemented which passes the handle to the ClientManager as the sole
+ argument.
+ </para>
+
+ <para>
+ Up until this point we have explored the intimate details of the
+ ClientManager service role without regard to its implementation.
+ Before going on to describe the current implementation we list the
+ responsibilities of the role:
+ </para>
+
+ <itemizedlist>
+ <listitem><para>
+ The ClientManager ties together the various client resources
+ composing the session of a client. It does so through the use
+ of the unique ClientKey identifying the client.
+ </para></listitem>
+
+ <listitem><para>
+ Add and drop methods enable control over the establishment of
+ new clients or closure to an existing client session both in
+ respect to the socket connection and the session along with all
+ outstanding requests. This way the service manages session
+ creation and destruction.
+ </para></listitem>
+
+ <listitem><para>
+ Services are provided to facilitate ClientKey propagation within
+ Thread contexts across non-staged server modules.
+ </para></listitem>
+
+ <listitem><para>
+ The service enables a master slave relationship between itself
+ and other dependent services to avoid cyclic dependency
+ detection by Avalon containers.
+ </para></listitem>
+
+ </itemizedlist>
+ </section>
+
+
+ <section>
+ <title>Implementation</title>
+
+ <para>
+ The ClientManager interface implemented by the ClientModule extends
+ the ConnectListener interface. Hence the ClientModule must
+ implement the methods declared within ConnectListener.
+ ConnectListener defines a single void method, connectPerformed,
+ which takes as its sole argument a ConnectEvent.
+ </para>
+
+ <para>
+ The signature of the connectPerformed method does not in any way
+ impose requirements on the way the ConnectEvent processing is
+ implemented. The ConnectListener implementation can handle the
+ event asynchronously or synchronously. The ClientModule is
+ presently implemented as a stage so the connectPerformed method
+ is implemented as a simple synchronized enqueue operation on the
+ event queue. Processing of the event is handled asynchronously
+ using threads from the stage thread pool to drive the event handler.
+ For more information on general stage implementation see the SEDA
+ implementation document. (Make me a link!)
+ </para>
+
+ <para>
+ ConnectEvents deliver client socket connections to the ClientManager
+ after a successful accept call on a server listner socket. The
+ event is enqueued on the stage event queue. The stage handler
+ thread awakens to dequeue the event, and hands off the event to a
+ stage worker thread for processing. During processing the event's
+ Socket is extracted, and a unique ClientKey object is generated
+ using the properties of the client's Socket. The ClientModule
+ generates the ClientKey from the Socket's TCP/IP connection
+ parameters: the client interface, the client port, the server
+ interface and the server connection port. The add service method
+ is then called using the ClientKey and the Socket.
+ </para>
+
+ <para>
+ The add() method implementation makes the association between the
+ ClientKey and the Socket for subsequent lookups. It also registers
+ the Socket's input and output streams with the respective IO
+ manager. The add() method called by the stage worker Thread
+ finishes off by creating a default ClientSession object for the
+ client. The default session uses a user Principal synonymous with
+ an anonymous user. The distinguished name is the empty string for
+ this default session. Later bind operations replace the Principal
+ with the Principal of the authenticated user. After creating the
+ default ClientSession it is bound to the ClientKey in a Map and
+ returned.
+ </para>
+
+ <para>
+ The association of ClientKeys within the context of the calling
+ thread is made using a ThreadLocal instance within the
+ threadAssociate() method. The association enables the lookup of
+ the ClientSession based on the Thread of execution. If the
+ executing Thread is mapped to a ClientKey within the ThreadLocal
+ object then a getClientSession() call with no arguments easily
+ retrieves the client's session without the ClientKey. The
+ getClientSession() method simply looks up the ClientKey associated
+ with the caller's Thread. After isolating the the ClientKey a
+ lookup on the session map using the ClientKey returns the
+ ClientSession of the calling thread. This way we avoid passing
+ around ClientKeys or ClientSession handles in simple modules called
+ between stages. Furthermore because the ClientManager is the master
+ module that all other modules can refer to, localization of session
+ data there is ideal.
+ </para>
+
+ <para>
+ Why have we implemented socket connection accepts using an event
+ model while making the connection close or dropping of a client a
+ matter of a simple synchronous call? Why not use a DisconnectEvent
+ and a DisconnectListener? Well, this was the case at first but we
+ found that the operation must proceed synchronously and there was
+ no need to have a stage for this task. Clients need to be dropped
+ as soon as an unbind request completes destroying all other requests
+ in the pipeline.
+ </para>
+ </section>
+
+ <section>
+ <title>Future</title>
+
+ <para>
+ Create InputStream and OutputStream wrappers to disable close
+ operations on these streams by the respective IO manager. Right
+ now the InputModule can close the client's input stream disabling
+ a client connection. Likewise the OutputModule can do the same with
+ the OuputStream of the client socket connection.
+ </para>
+ </section>
+
+ <section>
+ <title>Faults</title>
+
+ <para>
+ The module unnecessarily grabs a handle on the Decoder service.
+ </para>
+
+ <para>
+ The module needs to correctly handle the change of user principals
+ by destroying all outstanding request operations and properly timing
+ out old handles to ClientKeys and ClientSessions.
+ </para>
+ </section>
+</article>
Added: incubator/directory/eve/branches/start/src/docbook/design/controls.xml
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/docbook/design/controls.xml Thu Jun 24 00:06:35 2004
@@ -0,0 +1,124 @@
+<?xml version="1.0"?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD Simplified DocBook XML V4.1.2.5//EN"
+ "http://www.oasis-open.org/docbook/xml/simple/4.1.2.5/sdocbook.dtd">
+
+<article class="whitepaper">
+ <title>Controls</title>
+
+ <articleinfo>
+ <author><othername>akarasulu</othername></author>
+ <editor><othername>$Author: bearcej $</othername></editor>
+ <revhistory>
+ <revision>
+ <revnumber>$Revision: 1.3 $</revnumber>
+ <date>$Date: 2003/05/03 01:21:32 $</date>
+ <revdescription>
+ <para>
+$Log: controls.xml,v $
+Revision 1.3 2003/05/03 01:21:32 bearcej
+Remove tabs from doc files and fix linefeeds.
+
+Revision 1.2 2003/03/27 21:54:57 akarasulu
+Index exchange search control should be implemented.
+
+Revision 1.1 2003/03/27 21:34:14 akarasulu
+Start designs to implement some controls.
+
+ </para>
+ </revdescription>
+ </revision>
+ </revhistory>
+ </articleinfo>
+
+ <abstract>
+ <para>
+ The LDAPv3 protocol uses controls to send and receive additional data
+ to affect the behavior of predefined operations. Controls can be sent
+ along with any LDAP operation to the server. These are referred to as
+ request controls. For example, a "sort" control can be sent with an
+ LDAP search operation to request that the results be returned in a
+ particular order. Solicited and unsolicited controls can also be
+ returned with responses from the server. Such controls are referred to
+ as response controls. For example, an LDAP server might define a
+ special control to return change notifications. LDAPv3 controls are
+ defined in section 4.1.12 of RFC <ulink url=
+ "http://www.faqs.org/rfcs/rfc2251.html">2251</ulink>.
+ </para>
+ </abstract>
+
+ <section>
+ <title>Document TODOs:</title>
+ <itemizedlist>
+ <listitem><para>
+ Add diagrams.
+ </para></listitem>
+
+ <listitem><para>
+ Implement special search index exchange control to redirect or
+ return entries from server with sufficent indices to rapidly
+ conduct the search.
+ </para></listitem>
+
+ <listitem><para>
+ Implement LDAP Control Extension for Server Side Sorting of
+ Search Results, RFC 2891
+ </para></listitem>
+
+ <listitem><para>
+ Implement LDAP Extensions for Scrolling View Browsing of Search
+ Results, Internet-Draft Revision 4.
+ </para></listitem>
+
+ <listitem><para>
+ Implement LDAP Proxied Authorization Control, Revision 5
+ </para></listitem>
+
+ <listitem><para>
+ Implement LDAP Authentication Response Control, Internet-Draft
+ Revision 1
+ </para></listitem>
+
+ <listitem><para>
+ Implement Persistent Search: A Simple LDAP Change Notification
+ Mechanism, Internet-Draft Revision 2
+ </para></listitem>
+
+ <listitem><para>
+ Implement Manage DSA IT Control
+ </para></listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Design</title>
+
+ <para>
+ Add design here.
+ </para>
+ </section>
+
+
+ <section>
+ <title>Implementation</title>
+
+ <para>
+ Add implementation details here.
+ </para>
+ </section>
+
+ <section>
+ <title>Future</title>
+
+ <para>
+ Start this stuff.
+ </para>
+ </section>
+
+ <section>
+ <title>Faults</title>
+
+ <para>
+ Did not even start.
+ </para>
+ </section>
+</article>
Added: incubator/directory/eve/branches/start/src/docbook/design/decoder-module.xml
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/docbook/design/decoder-module.xml Thu Jun 24 00:06:35 2004
@@ -0,0 +1,258 @@
+<?xml version="1.0"?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD Simplified DocBook XML V4.1.2.5//EN"
+ "http://www.oasis-open.org/docbook/xml/simple/4.1.2.5/sdocbook.dtd">
+
+<article class="whitepaper">
+ <title>DecoderModule Implementation</title>
+
+ <articleinfo>
+ <author><othername>akarasulu</othername></author>
+ <editor><othername>$Author: bearcej $</othername></editor>
+ <revhistory>
+ <revision>
+ <revnumber>$Revision: 1.6 $</revnumber>
+ <date>$Date: 2003/05/03 01:43:08 $</date>
+ <revdescription>
+ <para>
+$Log: decoder-module.xml,v $
+Revision 1.6 2003/05/03 01:43:08 bearcej
+Add maven file to help generate server site.
+Modify graphic links again.
+Remove tabs from doc files and fix linefeeds.
+
+Revision 1.5 2003/05/03 01:21:32 bearcej
+Remove tabs from doc files and fix linefeeds.
+
+Revision 1.4 2003/03/25 23:17:13 akarasulu
+Finished off doc changes for use of lock objects.
+
+Revision 1.3 2003/03/24 13:22:27 akarasulu
+Made it so all modules use ClientKey lock objects for IO locking.
+
+Revision 1.2 2003/03/23 13:24:46 akarasulu
+Added these files from the ALPHA-0_7 branch.
+
+Revision 1.1.2.3 2003/03/15 17:24:52 bearcej
+Fixed figure tags to conform to simple docbook.
+Modified Files:
+ Tag: ALPHA-0_7
+ decoder-module.xml
+
+Revision 1.1.2.2 2003/03/10 23:43:29 akarasulu
+Moved links so that image references point to /image/design. Note that
+references do not have a [.] in front since the maven driven transforms
+automatically append [.] to references.
+
+Revision 1.1.2.1 2003/03/10 23:24:19 akarasulu
+Moved design documentation from docs/design to src/docbook/design.
+
+Revision 1.1.2.2 2003/03/06 23:11:26 akarasulu
+Proof read decoder module and added some content to protocol module docs.
+
+Revision 1.1.2.1 2003/03/03 04:39:08 akarasulu
+new docs and changes
+
+ </para>
+ </revdescription>
+ </revision>
+ </revhistory>
+ </articleinfo>
+
+ <abstract>
+ <para>
+ The DecoderModule implements the Decoder service interface which is
+ a subinterface of the InputListener interface. The InputListener
+ interface implements a single void method called inputReceived which
+ takes an InputEvent as its sole argument. The DecoderModule is thus
+ a glorified InputEvent listener or processor which decodes BER
+ encoded ASN.1 LDAPv3 request message envelopes into a request
+ LDAPMessage object. It essentially demarshals incomming requests
+ and is implemented as a server stage.
+ </para>
+ </abstract>
+
+ <section>
+ <title>Document TODOs:</title>
+ <itemizedlist>
+ <listitem><para>
+ Have a link to the InputModule documentation.
+ </para></listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Implementation</title>
+
+ <para>
+ As mentioned in the summary, the DecoderModule must implement only
+ one service method: inputReceived. The InputManager which is
+ implemented as a stage directly upstream of this Decoder stage,
+ has input handlers that monitor client Socket InputStreams for input
+ activity. Once input is dectected an InputEvent is generated and
+ handed off to the inputReceived method of the Decoder service. The
+ Decoder is then responsible for reading the request PDU from the
+ stream packaged within the InputEvent. The InputModule only detects
+ the input without interfering with or removing the content from the
+ stream.
+ </para>
+
+ <para>
+ The DecoderModule implements the Decoder service as a stage and so
+ its inputReceived method simply enqueues the InputEvent onto the
+ stage event queue and returns immediately. The event is processed
+ asynchronously by the worker threads of the DecoderModule stage
+ using the event handler initialized within the DecoderModule's
+ default constructor. Events are dequeued by the stage's driver
+ thread, and the code within the AbstractStage super class for this
+ module creates an annonymous Runnable to wrap and drive the call to
+ the stage's EventHandler using the dequeued event. For more details
+ regarding stage processing see the architecture and implementation
+ documentation for SEDA stages in LDAPd.
+ </para>
+
+ <figure>
+ <title>DecoderModule's InputEventHandler Sequence Diagram</title>
+ <graphic fileref=
+ "../images/InputEventHandlerHandleEvent.gif"/>
+ </figure>
+
+ <para>
+ The EventHandler for the DecoderModule is implemented as a named
+ inner class extending AbstractEventHandler. It is responsible for
+ processing the InputEvent in its handleEvent method which takes an
+ EventObject. The event argument must be an instance of an
+ InputEvent. The handleEvent method performs the work which is
+ driven by a stage worker thread. handleEvent extracts from the
+ InputEvent argument the ClientKey and an InputStream.
+ </para>
+
+ <para>
+ The extracted InputStream is used to read and decode BER encoded
+ ASN.1 LDAPv3 request message envelopes. The DecoderModule uses a
+ Snacc4J BERDecoder to demarshal the encoded stream bytes into an
+ LDAPMessage request envelope object. The Snacc4J compiler was
+ applied to generate this LDAPMessage stub class and other classes
+ whose instances are kept within a containment heirarchy with the
+ LDAPMessage at the root. The Snacc4J stub compiler generated these
+ classes from the LDAPv3 definitions specified in ASN.1 notation in
+ <ulink url="http://www.faqs.org/rfcs/rfc2251.html"> RFC 2251</ulink>
+ Appendix A. The generated classes are stored within the
+ ldapd-common subproject under the org.apache.ldap.common.ber.ldap_v3 package.
+ These classes are kept within the common subproject so that command
+ line ldap clients can be written both for protocol test suites and
+ production use. The Snacc4J BERDecoder instance is created to
+ specifically read from the InputStream extracted from the InputEvent
+ by invoking its constructor using the InputStream as the sole
+ argument. Then within a synchronized block on the input lock, the
+ decode method of the LDAPMessage object is called using the
+ BERDecoder instance as the sole argument. The LDAPMessage instance
+ was created earlier as an empty message void of content using the
+ default constructor. Once the decode method of the LDAPMessage
+ returns, the entire request PDU will have been read from the
+ client's InputStream and the LDAPMessage instance will contain a
+ tree of nested LDAPv3 defined object instances. At this point,
+ any further incomming bytes on the InputStream are the bytes to the
+ next request being sent by the client. For more info on how Snacc4J
+ reads and decodes bytes on the InputStream to generate the
+ LDAPMessage containment tree consult the
+ <ulink url="http://www.alphaworks.ibm.com/tech/snaccforjava">
+ Snacc4J website</ulink>. Since protocol engine request processors
+ must directly access the contents within the LDAPMessage envelope,
+ the structure of the containment tree is discussed in more detail
+ within their documentation.
+ </para>
+
+ <para>
+ All modules must assume the possibility of concurrent access to
+ client resources. In the case of the Decoder another thread may
+ attempt to read from the client InputStream while a request
+ extraction is in progress. Concurrent access would corrupt the
+ content stream removing bytes from the PDU. The Decoder must make
+ certain that no other thread is reading from the client's input
+ stream from which the decoder may be in the process of demarshalling
+ a request message. The ClientKey was explicitly designed to
+ centralize lock objects used for inter and intra module
+ synchronization. Lock objects for both the client's input and
+ output channels exist within the ClientKey. Two separate lock
+ objects were intentionally used to enable the writing of a response
+ while reading requests from the client at the same time. All
+ modules must use these lock objects to synchronize client IO
+ instead of using the supplied streams carried by events. The
+ objects carried by an event may not be those used for
+ synchronization in other modules. Use of these lock objects
+ instead guarrantee the use of the correct synchronization object.
+ </para>
+
+ <para>
+ Before leaving the synchronized block on the lock object, the
+ notifyAll method is called on the input lock. This wakes up blocked
+ threads waiting to read from the clients InputStream. The client
+ input monitor thread in the InputModule stage waits for this notify
+ to resume reads on the InputStream when the decoder is finished
+ demarshalling a request. Finally, with the LDAPMessage populated
+ a RequestEvent is created and packaged with the ClientKey and the
+ demarshaled LDAPMessage. Before returning from the handleEvent
+ method in the InputEventHandler the generated RequestEvent is
+ delivered to the ProtocolEngine to process the request. The
+ requestReceived method on the ProtocolEngine is used with the newly
+ created RequestEvent as the argument. Upon return the worker thread
+ dies and is reclaimed by the worker thread pool of the
+ DecoderModule stage.
+ </para>
+ </section>
+
+ <section id="future">
+ <title>Future</title>
+
+ <itemizedlist><listitem><para>
+ Think about writing a hard coded LDAPv3 specific encoder and decoder
+ using our own ASN.1 parser. The current stub compilers generate
+ stubs that implement or extend generalized encodind and decoding
+ classes to handle any kind of notation. This makes them less
+ efficient but more useful. If we hard code only for the the
+ LDAPv3 notation and use JDK1.4 new IO libraries we can customize and
+ optimize the encoder and decoder IO handling. Also the containment
+ tree generated by snacc in a decoded LDAPMessage is very mesy from
+ an OO perspective. All members are public and intuitive accessors
+ are not provided. Using these generated APIs for PDU construction
+ is tedious and the code is hard to maintain. Also collection APIs
+ are not used in Snacc4J Java stubs. A lot of ugliness within the
+ protocol processors would go away if we coded explicity for the
+ LDAPv3 definitions. The undertaking however is an open source
+ project on its own but well worth it considering the prevalence use
+ of ASN.1 and the BER, DER, and XER encodings. Considering the
+ performance impact of using direct memory IO on incoming and
+ outgoing messages for decoding and encoding buffers gets us excited.
+ </para></listitem></itemizedlist>
+
+ <itemizedlist><listitem><para>
+ Consider the use of a2j rather than Snacc4J. IBM's Snacc4J license
+ according to Peter Donald is not very compatable with the Apache 1.1
+ license. The a4j ASN.1 to Java Class compiler would better
+ compliment the Apache License. a2j is available
+ <ulink url="http://sourceforge.net/projects/a2j">here</ulink>, but
+ it may not be mature enough for now.
+ </para></listitem></itemizedlist>
+
+ <itemizedlist><listitem><para>
+ Potential use of new IO APIs to decode. Will this be necessary
+ if channels are interchangeable or wrappable by InputStreams. We
+ will always have to generate a DOM like containment tree of the
+ request message to access it. Perhaps a SAX like implementation
+ can be found but will that be feasible with the manner in which
+ request processors operate. Do we want to cache copies of this
+ data in multiple formes? Answer is no way. Right now it is stored
+ in the LDAPMessage tree as well as parameters within the protocol
+ request processors. It would be nice to just maintain one copy of
+ the information set stored in each request.
+ </para></listitem></itemizedlist>
+ </section>
+
+ <section>
+ <title>Faults</title>
+
+ <itemizedlist><listitem><para>
+ Uses Snacc4J.
+ </para></listitem></itemizedlist>
+ </section>
+</article>
Added: incubator/directory/eve/branches/start/src/docbook/design/encoder-module.xml
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/docbook/design/encoder-module.xml Thu Jun 24 00:06:35 2004
@@ -0,0 +1,165 @@
+<?xml version="1.0"?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD Simplified DocBook XML V4.1.2.5//EN"
+ "http://www.oasis-open.org/docbook/xml/simple/4.1.2.5/sdocbook.dtd">
+
+<article class="whitepaper">
+ <title>Module Implementation</title>
+
+ <articleinfo>
+ <author><othername>akarasulu</othername></author>
+ <editor><othername>$Author: bearcej $</othername></editor>
+ <revhistory>
+ <revision>
+ <revnumber>$Revision: 1.6 $</revnumber>
+ <date>$Date: 2003/05/03 01:45:23 $</date>
+ <revdescription>
+ <para>
+$Log: encoder-module.xml,v $
+Revision 1.6 2003/05/03 01:45:23 bearcej
+Refix image URLs
+
+Revision 1.5 2003/05/03 01:43:08 bearcej
+Add maven file to help generate server site.
+Modify graphic links again.
+Remove tabs from doc files and fix linefeeds.
+
+Revision 1.4 2003/05/03 01:21:32 bearcej
+Remove tabs from doc files and fix linefeeds.
+
+Revision 1.3 2003/04/08 02:29:55 bearcej
+* Clean up project.properties
+* Fix logos in project.xml
+* Fix links to image files in docs
+
+Revision 1.2 2003/03/23 13:24:46 akarasulu
+Added these files from the ALPHA-0_7 branch.
+
+Revision 1.1.2.4 2003/03/15 17:34:19 bearcej
+Fix href to ResponseEventHandlerHandleEvent.gif
+
+Revision 1.1.2.3 2003/03/15 17:25:35 bearcej
+Fix figure tags to conform to simple docbook.
+Modified Files:
+ Tag: ALPHA-0_7
+ encoder-module.xml
+
+Revision 1.1.2.2 2003/03/10 23:43:30 akarasulu
+Moved links so that image references point to /image/design. Note that
+references do not have a [.] in front since the maven driven transforms
+automatically append [.] to references.
+
+Revision 1.1.2.1 2003/03/10 23:24:19 akarasulu
+Moved design documentation from docs/design to src/docbook/design.
+
+Revision 1.1.2.2 2003/03/09 00:36:54 akarasulu
+Finished encoder docs and refactored inner annonymous handler to be a
+named inner class.
+
+Revision 1.1.2.1 2003/03/03 04:49:25 akarasulu
+Added as placeholders for now.
+
+ </para>
+ </revdescription>
+ </revision>
+ </revhistory>
+ </articleinfo>
+
+ <abstract>
+ <para>
+ The EncoderModule implements the Encoder service interface as a
+ stage within the server. It asynchronously processes ResponseEvents
+ in parallel, encoding the contents of the response message envelope
+ packaged into the ResponseEvent. Effectively the encoder is
+ responsible for mashaling the contents of the LDAPMessage response
+ envelope filled with Snacc4J compiler generated class instances into
+ a byte buffer.
+ </para>
+ </abstract>
+
+ <section>
+ <title>Document TODOs:</title>
+ <itemizedlist>
+ <listitem><para>
+ Add diagrams.
+ </para></listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Implementation</title>
+
+ <para>
+ The Encoder service interface extends the ResponseListener interface
+ besides defining extra synchronous processing methods. The single
+ ResponseListener method, responseComposed(), gives the staged module
+ its event processing character. The method accepts a ResponseEvent
+ as its argument. The implementation simply enqueues the event onto
+ the stage event queue and returns immediately. The stage driver
+ thread as in all stages with the server, dequeues the event and
+ dedicates a worker thread to process the event. Again a
+ intermediate annonymous Runnable implementation is used to have the
+ worker thread drive the call to the stage event handler.
+ </para>
+
+ <para>
+ A single method is directly defined within the Encoder interface
+ rather than being inherited from ResponseListener: the encode
+ method. The encode method is implemented by the module as a
+ synchronous call to encode a message. Meaning a worker thread does
+ not drive the marshaling process. The thread of the caller drives
+ the encoding. This synchronous version requires no event hence it
+ is not part of the ResponseListener interface but is defined
+ directly within the Encoder interface. The upstream need within the
+ search request processor to synchronously deliver search entry
+ response message envelopes has resulted in this synchronous method,
+ encode. It is only utilized within the search request processor of
+ the protocol engine module.
+ </para>
+
+ <para>
+ Upon the dequeue of a ResponseEvent and the subsequent assignment
+ of a worker thread to process the event within the event handler,
+ the real work of marshaling the response message envelope can be
+ done. A named inner class, ResponseEventHandler, is used to
+ implement the stage event handler. The handleEvent() method of this
+ class is used to process the ResponseEvent in the execution context
+ of a stage worker thread. Below is a sequence diagram showing the
+ high level steps in processing the ResponseEvent within the event
+ handler.
+ </para>
+
+ <figure>
+ <title>EncoderModule's ResponseEventHandler Sequence Diagram</title>
+ <graphic fileref="../images/ResponseEventHandlerHandleEvent.gif"/>
+ </figure>
+
+ <para>
+ The client key of the client which generated the ResponseEvent and
+ the response message envelope are first extracted from the event
+ argument. The message is encoded into a byte buffer by calling the
+ synchronous encode method. Then the resultant marshaled PDU in the
+ byte array is used along with the client key to construct an
+ OutputEvent. Before the handler completes and the driving worker
+ thread dies, the event is delivered to the downstream OutputManager
+ stage to be processed asynchronously via the writeResponse() method
+ on the OutputManager service interface.
+ </para>
+ </section>
+
+ <section>
+ <title>Future</title>
+
+ <para>
+ The same future enhancements mentioned for the decoder hold for
+ the encoder.
+ </para>
+ </section>
+
+ <section>
+ <title>Faults</title>
+
+ <para>
+ Find some faults! Believe me you they exist.
+ </para>
+ </section>
+</article>
Added: incubator/directory/eve/branches/start/src/docbook/design/event-module.xml
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/docbook/design/event-module.xml Thu Jun 24 00:06:35 2004
@@ -0,0 +1,343 @@
+<?xml version="1.0"?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD Simplified DocBook XML V4.1.2.5//EN"
+ "http://www.oasis-open.org/docbook/xml/simple/4.1.2.5/sdocbook.dtd">
+
+<article class="whitepaper">
+ <title>Module Implementation</title>
+
+ <articleinfo>
+ <author><othername>akarasulu</othername></author>
+ <editor><othername>$Author: bearcej $</othername></editor>
+ <revhistory>
+ <revision>
+ <revnumber>$Revision: 1.3 $</revnumber>
+ <date>$Date: 2003/05/03 01:21:32 $</date>
+ <revdescription>
+ <para>
+$Log: event-module.xml,v $
+Revision 1.3 2003/05/03 01:21:32 bearcej
+Remove tabs from doc files and fix linefeeds.
+
+Revision 1.2 2003/03/23 13:24:46 akarasulu
+Added these files from the ALPHA-0_7 branch.
+
+Revision 1.1.2.1 2003/03/10 23:24:20 akarasulu
+Moved design documentation from docs/design to src/docbook/design.
+
+Revision 1.1.2.3 2003/03/09 22:22:35 akarasulu
+For all practical purposes the EventModule documentation is considered
+done. It is not really used yet and when it is we can fill in the
+relavent sections.
+
+Revision 1.1.2.2 2003/03/09 22:12:48 akarasulu
+Moved the event-model-chapter.xml content into the event-module.xml file.
+
+Revision 1.1.2.1 2003/03/03 04:49:25 akarasulu
+Added as placeholders for now.
+
+ </para>
+ </revdescription>
+ </revision>
+ </revhistory>
+ </articleinfo>
+
+ <abstract>
+ <para>
+ This chapter discusses ldapd's server side protocol event model,
+ its use, design and implementation. It does not cover the SEDA
+ event model that loosely couples stages within the server. For lack
+ of a better term we refer to this system of events, listeners and
+ sources as the protocol event model.
+ </para>
+ </abstract>
+
+ <section>
+ <title>Document TODOs:</title>
+ <itemizedlist>
+ <listitem><para>
+ Add diagrams.
+ </para></listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>
+ Potential Uses For Pre And Post Protocol Events
+ </title>
+
+ <para>
+ During the course of processing LDAP requests, subsystems will need
+ to transparently inject their services. An event model provides a
+ decoupled way for these systems to communicate. Listeners abstract
+ and decouple interfaces on targets while source interfaces used to
+ register listeners decouple the event source. Events simply carry
+ payloads of information required to respond appropriately. Several
+ subsystems will leverage the event model to transparently effect
+ server operations without impossing dependence between themselves
+ and other modules within the server. This section discusses various
+ systems that would benefit from an event model.
+ </para>
+
+ <para>
+ Authorization is an excellent candidate for using the event model.
+ When registered for events, the authorization module will recieve
+ events with profile information and other context information
+ describing the operation being performed. Of course it makes no
+ sence to have the authorization module recieve these events after an
+ operation completes. So it must recieve pre events to actually
+ intervene in the process, thereby preventing unauthorized requests
+ from being serviced. Event delivery must notify synchronously of
+ the pending event to allow for the authorization module to
+ intervene.
+ </para>
+
+ <para>
+ A trigger subsystem or module would also depend on an event model.
+ Triggers in the RDBMS world are specified using a set of operations
+ with a modifier used to determine when the trigger fires. Triggers
+ this way can fire before or after an operation takes place.
+ Triggers communicate their objections to the rest of the system by
+ raising exceptions when conditions are not met. Some triggers are
+ required after an operation has completed. Regardless of the
+ purpose of a trigger, correct trigger operation is dependent on the
+ receipt of events by the trigger subsystem before and after protocol
+ operations occur.
+ </para>
+
+ <para>
+ Master servers with replicas need to recieve entry change
+ notification events. Master servers contain a master replication
+ module. This module enqueue's change events onto the replication
+ queues of the replication subsystem. These events are used to
+ asynchronously communicate the changes that need to take place to
+ keep replica servers synchronized with master server DIB (Direcotry
+ Information Base) changes.
+ </para>
+ </section>
+
+ <section>
+ <title>
+ Aspects Of The Protocol Event Model
+ </title>
+
+ <para>
+ When discussing events, we need to qualify their delivery as
+ synchronous or asynchronous. Different situations may warrent
+ different delivery timing requirements. Events are triggered by
+ event sources, then delivered to targets that posses event listener
+ handler methods. The design of a protocol event model requires the
+ clear definition of the events, targets and sources involved. These
+ concerns and their details must be explored for all conceivable use
+ cases for the protocol event model.
+ </para>
+
+ <para>
+ Listeners registered to receive events often need to effect the
+ outcome of an operation based on some condition. The authorization
+ module is a good example of such a listener. It must check to see
+ if each protocol operation is allowed to proceed based on the
+ authorization profile of the user and the parameters of the
+ operation. If for some reason the user is not allowed to perform
+ the operation, the authorization subsystem must stop the operation.
+ To stop the execution of an operation the delivery of the event must
+ occur before the operation begins. The operation must be kept in a
+ suspended state until the authorization module can evaluate whether
+ access is granted or denied. The situation requires synchronous
+ event delivery. If the event is delivered synchronously before the
+ operation begins, the operation waites until the event handlers of
+ the listeners complete - meaning until the authorization module
+ evaluates the operation. With synchronous deliveray a runtime
+ authorization exception can be raised to stop the current executing
+ thread. The exception tunnels back up the exception stack of the
+ driving processor thread. The thread driver traps all exceptions
+ reporting the reason for the failure by packaging the contents of
+ the authorization exception into a return message to the client.
+ </para>
+
+ <para>
+ Synchronous event delivery best suites the needs of the
+ authorization module. The module easily prevents an operation from
+ executing by throwing an exception. Because the thread executing
+ the operation is the same thread calling the listener handlers, an
+ exception thrown by a handler interupts the operation. Most use
+ cases for an event model are satisfied by a synchronous delivery
+ mechanism. Synchronous delivery of events can be handled
+ asynchronously by target modules. For example replication is best
+ handled asynchronously. Upon receiving an event that represents the
+ alteration of a mastered DIB the master replication module may use
+ another thread to asynchronously push these events onto a
+ replication event queue. The delivery of the protocol event is
+ synchronous yet how it is handled becomes asynchronous in the
+ implementation replication module. Synchronous event delivery does
+ enable listeners to alter the outcome of an operation. This is
+ great if you need to affect the outcome. This is not so good if you
+ do not want to give such power over the outcome to listener
+ handlers.
+ </para>
+
+ <para>
+ The power to effect the outcome or delay the outcome is given to
+ every listener handler invoked by a processing thread. Conditional
+ traps can however be used to catch exceptions and ignore them,
+ thereby allowing the operation to continue regardless of bad
+ listener code or listener code objecting to the operation. This
+ would enable a finer degree of control over how much power is handed
+ off to the event handlers of registered listeners. Modifiers that
+ determine the mode of operation for the registered listener would be
+ part of a listener specification. In terms of delaying the outcome,
+ there is very little that can be done outside of using processor
+ thread controls similar to those used for search controls. For
+ example time limits are used to constrain a search request. Similar
+ constructs can be used to contstrain the maximum amount of time
+ allowed for a thread to spend processing an event. If the the
+ thread spends too much time in listener event handlers the operation
+ can be abandoned. Again parameters used to limit the amount of time
+ a thread can spend in the listener handlers should be part of a
+ listener specification defined perhaps at listener registration
+ time. Perhaps the maximum time limit can be specified based on the
+ event type delivered instead of the listener registered. In this
+ case the delivery specification must be given with every event
+ fired. There are several ways in which the behavior of synchronous
+ event delivery can be managed but overall synchronous event delivery
+ is the best way to go for our internal protocol event model.
+ </para>
+
+ <para>
+ Events can be fired from anywhere and delivered to any listener in
+ any order. There really is no difference between a synchronous
+ event delivery method call and any other method call. Event
+ listeners simply comply with an interface for recieving a handle on
+ a constant event delivered to each listener. These listeners are
+ called one after the other by the same thread in a firing loop.
+ Any module or operation in the server may initiate the firing of an
+ event. The firing component is logically the source of the event,
+ in that it drove the creation of the event and triggered its
+ delivery to the target listener interface method. The source may
+ be coming in from anywhere. Obviously the protocol module can be
+ the source, the JNDI provider can also be the source when the JNDI
+ interfaces are used to make changes. The thread used to drive the
+ change obviously comes from the protocol module as a processor
+ thread. This will undoubtedly change as we begin to enable timer
+ driven triggers in the server which are scheduled to run stored
+ procedures as a particular user. These will be driven by a timer
+ thread or a thread from a central pool.
+ </para>
+
+ <para>
+ Any caller to a listener handler method has the potential to be an
+ event source. How then do we control and manage event sources and
+ event listeners? We cannot and should not constrain event inducing
+ sources because the picture may change with time as parts of the
+ server are improved. Sources may change with server module
+ configurations and so should be left undefined. We should however
+ constrain listeners to implement specified interfaces. New
+ listeners developed can easily implement these interfaces which
+ specify the event types listened for.
+ </para>
+
+ <para>
+ As discussed listeners will need to register themselves with ideally
+ the event source that generates and delivers the event. This
+ however need not be the case. With many event models the source
+ requests delivery of events to listeners using a third party which
+ is a central fixture. Sure listeners are registered at the source
+ for events but this need not be the case either. A central
+ registry can be used to act as a hub for all events generated in
+ the server. The registry provides interfaces for listeners to
+ register for events. It can also provide interfaces for firing
+ various events on behalf of the event source. Under such a
+ configuration we would centralize the machinery for the lookup of
+ listeners and the delivery of events based on the event source.
+ All the timing based requirements of event delivery and the traps
+ used to prevent listener interference can be implemented there in
+ a central event manager. Note once again this is separate from the
+ asynchonous events used across server stages.
+ </para>
+
+ <para>
+ Events are modeled to represent protocol operations. LDAP abandon,
+ add, bind, compare, delete, modify, modify DN, search and unbind
+ operations are represented using their own respective event types
+ that derive from one common abstract ProtocolEvent ancestor. The
+ ProtocolEvent is the abstract based where common functionality or
+ data can be added to the set of events in the model.
+ </para>
+
+ <para>
+ Protocol operations may not directly be driving the firing of
+ events in all cases. Scheduled maintainence operations triggered
+ by a timer may fire events as a consequence of executing the stored
+ procedures they invoke. These stored procedures induce changes
+ through the internal server side JNDI provider. No LDAP operation
+ recieved from a client as a PDU (Protocol Data Unit) is associated
+ with the events fired by the executing stored procedure. These
+ phantom events are flagged as such via a boolean property. This
+ property determines whether or not a physical PDU was delivered
+ for the event. Client operations against the server may raise
+ triggers that fire stored procedures which operate on a DIT within
+ the server. These indirect trigger driven changes will fire
+ events that are not associated with a physical PDU and hence will
+ have the respective flag set to false. These events are part of
+ the event cascade centrally rooted at the original event that
+ started the cascade. We need to differentiate between the root
+ of an event cascade and all other descendent events that may fire
+ as a result of the original root event. Protocol events are
+ designed to keep a handle on a root event. This way the event
+ cascade tree can be represented using parent child associations.
+ The parent event this way is represented as having triggered a
+ child in a cascade of event firings. The root event of the cascade
+ refers back to itself as the cascade root and also offers an
+ interface to check if it is the root of the cascade this way. In
+ both of these cases (scheduled firing and indirect cascade driven
+ firing) no protocol activity exists yet protocol events will be
+ fired as if a comparable protocol operation were inducing the event.
+ The event model captures all the information needed by a listener
+ to differentiate how and why the event was fired. By determining
+ if the event is or is not the root of a cascade and if it is
+ directly associated with a physical PDU listeners can take the
+ appropriate action after interpreting the context of the event.
+ </para>
+
+ <para>
+ Often one event may trigger another event to be fired. At times
+ this will naturally result in an event cascade which may be a
+ desirable side effect. These cascades may result in unbounded
+ cyclic firings within the server if listener event handlers are not
+ carefully designed. The server must detect these dangerous
+ conditions and halt the firing of subsequent events. Luckily since
+ synchronous delivery is used we can track the tree of events
+ representing the event cascade by associating the structure with
+ the driving thread. Using this tree carried with the thread of
+ execution we can determine if a cyclic firing is occuring and
+ terminate the cascade before a StackOverflowError results. A
+ central event manager is perfect for placing such code to detect
+ unbounded event cascades and managing a weak thread context hash
+ for the event cascade tree structure.
+ </para>
+ </section>
+
+ <section>
+ <title>Implementation</title>
+
+ <para>
+ Add implementation details here.
+ </para>
+ </section>
+
+ <section>
+ <title>Future</title>
+
+ <para>
+ Add future enhancements here.
+ </para>
+ </section>
+
+ <section>
+ <title>Faults</title>
+
+ <para>
+ Add faults here.
+ </para>
+ </section>
+
+</article>
Added: incubator/directory/eve/branches/start/src/docbook/design/input-module.xml
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/docbook/design/input-module.xml Thu Jun 24 00:06:35 2004
@@ -0,0 +1,213 @@
+<?xml version="1.0"?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD Simplified DocBook XML V4.1.2.5//EN"
+ "http://www.oasis-open.org/docbook/xml/simple/4.1.2.5/sdocbook.dtd">
+
+<article class="whitepaper">
+ <title>Input Module Implementation</title>
+
+ <articleinfo>
+ <author><othername>akarasulu</othername></author>
+ <editor><othername>$Author: bearcej $</othername></editor>
+ <revhistory>
+ <revision>
+ <revnumber>$Revision: 1.6 $</revnumber>
+ <date>$Date: 2003/05/03 01:45:23 $</date>
+ <revdescription>
+ <para>
+$Log: input-module.xml,v $
+Revision 1.6 2003/05/03 01:45:23 bearcej
+Refix image URLs
+
+Revision 1.5 2003/05/03 01:43:08 bearcej
+Add maven file to help generate server site.
+Modify graphic links again.
+Remove tabs from doc files and fix linefeeds.
+
+Revision 1.4 2003/05/03 01:21:32 bearcej
+Remove tabs from doc files and fix linefeeds.
+
+Revision 1.3 2003/03/24 13:22:27 akarasulu
+Made it so all modules use ClientKey lock objects for IO locking.
+
+Revision 1.2 2003/03/23 13:24:46 akarasulu
+Added these files from the ALPHA-0_7 branch.
+
+Revision 1.1.2.3 2003/03/15 17:11:40 bearcej
+Fixed figure tags to conform to simple docbook.
+Modified Files:
+ Tag: ALPHA-0_7
+ input-module.xml
+
+Revision 1.1.2.2 2003/03/10 23:43:31 akarasulu
+Moved links so that image references point to /image/design. Note that
+references do not have a [.] in front since the maven driven transforms
+automatically append [.] to references.
+
+Revision 1.1.2.1 2003/03/10 23:24:20 akarasulu
+Moved design documentation from docs/design to src/docbook/design.
+
+Revision 1.1.2.2 2003/03/03 04:39:08 akarasulu
+new docs and changes
+
+Revision 1.1.2.1 2003/03/02 22:29:22 akarasulu
+Added input module architecture and implementation document.
+
+ </para>
+ </revdescription>
+ </revision>
+ </revhistory>
+ </articleinfo>
+
+ <abstract>
+ <para>
+ The InputModule implements the InputManager service interface and in
+ doing so is responsible for detecting input on the client Socket's
+ InputStream.
+ </para>
+ </abstract>
+
+ <section>
+ <title>Document TODOs:</title>
+ <itemizedlist>
+ <listitem><para>
+ Add diagrams.
+ </para></listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Implementation</title>
+
+ <para>
+ The InputManager service interface implemented by this module
+ defines two symetric methods for client input management. These
+ methods are register and unregister. The register method takes two
+ arguments: the client socket's ClientKey and its InputStream. The
+ unregister method takes a sole ClientKey argument to undo the
+ affects of the register method. Through these interface methods the
+ service provides input detection on registered client InputStreams.
+ Detection of incomming client requests results in the creation and
+ delivery of InputEvents to the request Decoder.
+ </para>
+
+ <para>
+ The InputModule is not a staged module. Hence stage events can not
+ be enqueued onto this module. Unlike a simple module it has an
+ internal thread pool. Pool threads execute the code which detects
+ input on each client socket InputStream.
+ </para>
+
+ <para>
+ The monitoring process begins when clients are registered. The
+ register call first maps a ClientKey argument to an InputStream
+ argument using a Map. The Map enables rapid InputStream lookups
+ based on ClientKeys. The register method then creates and
+ instantiates an InputStreamMonitor which happens to implement the
+ Runnable interface. The InputStreamMonitor's run method contains
+ the logic used to detect input on the client Socket's InputStream
+ and is executed by threads from this module's sole thread pool.
+ The register method, immediately before returning, assigns and
+ starts a Thread from the pool to drive the Runnable
+ InputStreamMonitor. Hence an InputStreamMonitor, a driving thread,
+ and a ClientKey to InputStream Map entry are created for each
+ registered client.
+ </para>
+
+ <figure>
+ <title>register() Method Sequence Diagram </title>
+ <graphic fileref=
+ "../images/InputModuleRegister.gif"/>
+ </figure>
+
+ <para>
+ The Runnable InputStreamMonitor waits blocked on a
+ PushbackInputStream. The PushbackInputStream wraps the client
+ Socket's InputStream so reads from it actually read from the client.
+ The blocking call is on the read() method without arguments which
+ returns a single byte of data from the underlying InputStream. When
+ read() returns the byte read is pushed back to enable the decoder
+ to read a complete protocol request. An InputEvent is created in
+ response using the ClientKey with the PushbackInputStream as event
+ members. The InputEvent is then delivered to the Decoder service
+ which extends the InputListener interface. The InputListener method
+ used to deliver the event is inputReceived() which takes a sole
+ InputEvent argument. Once the Decorder extracts the PDU from the
+ PushbackInputStream the monitor then loops once again to listen
+ for incomming request PDUs. The process continues for each request
+ PDU delivered to the client. If the client disconnects abruptly
+ an IOException occurs. Once caught the client is dropped and the
+ loop terminates by returning from the run method. Dropped clients
+ are handled by testing for key expiration or responding to a
+ KeyExpiryException. In either case the InputStreamMonitor's loop
+ terminates and the run method returns.
+ </para>
+
+ <para>
+ The run() method synchronizes on the input lock object of the client
+ before going into the while loop which detects input on the stream.
+ This is necessary to prevent reads while a decoder extracts the PDU.
+ The loop makes sure that it does not reread from the stream on the
+ same incomming PDU after input detection by sitting in a wait state.
+ The indefinate wait() is called on the input lock object after the
+ event is handed off to the Decoder. The worker thread is awakened
+ to continue monitoring for input after the Decoder completes the
+ full read of the request PDU. The Decoder awakens the worker by
+ calling notifyAll() on the input lock object immediately after the
+ PDU read.
+ </para>
+ </section>
+
+ <section>
+ <title>Future</title>
+
+ <itemizedlist><listitem><para>
+ Because blocking IO is used, a thread pool is needed to assign a
+ thread to a Runnable input handler to monitor each client Socket's
+ InputStream. This is unavoidable with any JVM below version 1.4
+ since non-blocking IO is not provided. JDK 1.4 introduces the new
+ IO packages that have selectable IO channels where a single thread
+ can be used to monitor multiple input channels. For a stateful
+ protocol server non-blocking IO is critical otherwise a thread is
+ required for the management of IO on each client. Stateful protocol
+ servers (like LDAPd) can NOT scale well as the number of concurrent
+ clients increase. This was a serious limitation for pure Java
+ stateful protocol servers up until JDK1.4. Native libraries
+ could have been used while sacrificing portability but this would
+ have problems with Java purists. With a one to one ratio of clients
+ to threads, performance will degrade rapidly after 50 clients.
+ Non-blocking IO should allow for thousands of concurrent client
+ connections with minimal performance hits. Furthermore the overhead
+ of SEDA in LDAPd will not pay off until non-blocking IO is used.
+ Expect the use of NIO libraries or their equivalent in a beta
+ release.
+ </para></listitem></itemizedlist>
+
+ <itemizedlist><listitem><para>
+ We have specifically modeled the modules dealing with client IO as
+ granular as possible to reflect a separation of concerns. Rather
+ than use larger modules to handle the detection and read from a
+ stream we created two separate modules: one for IO detection and
+ another to actually read from the client's stream. The same
+ approach was applied with respect to the detection of client
+ connections on the server socket. If client connection accepts,
+ input detection and input reads were bundled into one module, the
+ implementation would have been extremely trivial yet very coupled
+ and hard to manage without complete rewrites. The listener, input,
+ output, encoder, decoder and client modules have been defined to
+ handle a small part of client IO management functions. This
+ approach should make it easier to implement plugable non-blocking
+ replacements for most of these modules with minimal changes to their
+ service interfaces or affecting other services associated with IO
+ management.
+ </para></listitem></itemizedlist>
+ </section>
+
+ <section>
+ <title>Faults</title>
+ <itemizedlist>
+ <listitem><para>
+ Does not presently use non-blocking IO.
+ </para></listitem>
+ </itemizedlist>
+ </section>
+</article>
Added: incubator/directory/eve/branches/start/src/docbook/design/jndi-provider-module.xml
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/docbook/design/jndi-provider-module.xml Thu Jun 24 00:06:35 2004
@@ -0,0 +1,169 @@
+<?xml version="1.0"?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD Simplified DocBook XML V4.1.2.5//EN"
+ "http://www.oasis-open.org/docbook/xml/simple/4.1.2.5/sdocbook.dtd">
+
+<article class="whitepaper">
+ <title>Module Implementation</title>
+
+ <articleinfo>
+ <author><othername>akarasulu</othername></author>
+ <editor><othername>$Author: akarasulu $</othername></editor>
+ <revhistory>
+ <revision>
+ <revnumber>$Revision: 1.4 $</revnumber>
+ <date>$Date: 2003/08/22 21:15:54 $</date>
+ <revdescription>
+ <para>
+$Log: jndi-provider-module.xml,v $
+Revision 1.4 2003/08/22 21:15:54 akarasulu
+Merged changes made in the USING_PROVIDER_FRAMEWORK branch of the
+server. I don't suspect she will be working well at this point. Lots
+of overhauling required now.
+
+Revision 1.2.2.1 2003/05/19 00:42:41 akarasulu
+Working on getting better integration with JNDI and embedding result codes
+into the exception message strings.
+
+Revision 1.2 2003/03/23 13:24:46 akarasulu
+Added these files from the ALPHA-0_7 branch.
+
+Revision 1.1.2.1 2003/03/10 23:24:20 akarasulu
+Moved design documentation from docs/design to src/docbook/design.
+
+Revision 1.1.2.1 2003/03/03 04:49:25 akarasulu
+Added as placeholders for now.
+
+ </para>
+ </revdescription>
+ </revision>
+ </revhistory>
+ </articleinfo>
+
+ <abstract>
+ <para>
+ </para>
+ </abstract>
+
+ <section>
+ <title>Document TODOs:</title>
+ <itemizedlist>
+ <listitem><para>
+ Add diagrams.
+ </para></listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Implementation</title>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+ </section>
+
+ <section>
+ <title>Future</title>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+ </section>
+
+ <section>
+ <title>Faults</title>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+ </section>
+
+ <section>
+ <title>Notes</title>
+
+ <para>
+ When the JNDI provider is used directly outside of the path through
+ the protocol module, there is no ClientKey or ClientSession
+ associated with the thread of execution. One cannot use the client
+ key to access the ClientSession through the ClientManager interface.
+ The identity of the user is unknown currently. Code responsible for
+ setting the operational attributes within the UnifiedBackend or
+ nexus as it is referred to, requires the prinicipal of the user in
+ order to set attributes like the creatorsName and the modifiersName.
+ Another means is required to establish the identity of the user on
+ whose behalf a non-protocol engine thread executes through the JNDI
+ provider.
+ </para>
+
+ <para>
+ JNDI inherently passes around parameters pertaining to its mode of
+ operation and to the identity of the user using environment
+ parameters and properties. Things like the user prinicipal and the
+ password of the user are inherited by one context which can in turn
+ lead to another. In our particular situation calls on a Contexts
+ and their subclasses result in calls by the server side JNDI
+ provider to the nexus module. These calls are made with respect to
+ a single context. When calls are made on the nexus, the nexus
+ methods need to be able to access environment parameters without
+ passing around extra arguments. Access to environment parameters
+ no matter how deep the calls into the nexus and its registered
+ backends should occur on an as needed basis. The nexus, backends
+ and other modules need to be able to differentiate between calls
+ made by protocol module worker threads and other threads going
+ through the JNDI provider bypassing the protocol.
+ </para>
+
+ <para>
+ In conclusion, every module used to conduct backend operations must
+ first be able to differentiate between a protocol driven call and a
+ protocol bypassing call. Secondly parameters required to conduct
+ operations must be extracted either through JNDI environment
+ properties or through a ClientSession. To do so threads must be
+ tracked centrally somewhere and associated with these objects. When
+ all operations complete or another context is used by the same
+ thread the relationship is dismantled and another one is
+ established.
+ </para>
+
+ <para>
+ The ClientManager again is the perfect candidate for centrally
+ managing thread to Context associations. After all non-protocol
+ driven calls through the JNDI provider are still server clients yet
+ not in the protocol sense as remote processes but in the method call
+ sense as local servers embedding LDAPd in the same process space.
+ Another reason why the ClientManager is perfect for this task is due
+ to the ability to referrence it from every module in the server.
+ The ClientManager is the central master module. Other modules
+ implementing the ClientManagerSlave interface can get a handle on
+ the ClientManager service without imposing cyclic dependencies
+ within an Avalon Container like Phoenix. It is the best place to
+ keep data related to a JNDI contexts for referrence later on by
+ modules requiring JNDI environment parameters without passing around
+ environments as arguments in each method call.
+ </para>
+
+ <para>
+ An overload to the threadAssociate method taking a LdapContext as
+ its only argument can be implemented to associate a thread with a
+ JNDI LdapContext. The context and its environment can then be
+ referred at any time during the execution of method calls against
+ the server's backend nexus. The extraction of the user principal
+ to set operational attributes simple requires a test to see if a
+ JNDI LdapContext is associated with the calling thread. If so the
+ environment of the context is access to get the user principal
+ associated with the context and hence the executing thread.
+ </para>
+ </section>
+
+</article>
Added: incubator/directory/eve/branches/start/src/docbook/design/listener-module.xml
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/docbook/design/listener-module.xml Thu Jun 24 00:06:35 2004
@@ -0,0 +1,172 @@
+<?xml version="1.0"?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD Simplified DocBook XML V4.1.2.5//EN"
+ "http://www.oasis-open.org/docbook/xml/simple/4.1.2.5/sdocbook.dtd">
+
+<article class="whitepaper">
+ <title>Listener Module Implementation</title>
+
+ <articleinfo>
+ <author><othername>akarasulu</othername></author>
+ <editor><othername>$Author: bearcej $</othername></editor>
+ <revhistory>
+ <revision>
+ <revnumber>$Revision: 1.6 $</revnumber>
+ <date>$Date: 2003/05/03 01:45:23 $</date>
+ <revdescription>
+ <para>
+$Log: listener-module.xml,v $
+Revision 1.6 2003/05/03 01:45:23 bearcej
+Refix image URLs
+
+Revision 1.5 2003/05/03 01:43:08 bearcej
+Add maven file to help generate server site.
+Modify graphic links again.
+Remove tabs from doc files and fix linefeeds.
+
+Revision 1.4 2003/05/03 01:21:32 bearcej
+Remove tabs from doc files and fix linefeeds.
+
+Revision 1.3 2003/04/08 02:29:55 bearcej
+* Clean up project.properties
+* Fix logos in project.xml
+* Fix links to image files in docs
+
+Revision 1.2 2003/03/23 13:24:46 akarasulu
+Added these files from the ALPHA-0_7 branch.
+
+Revision 1.1.2.3 2003/03/15 17:21:07 bearcej
+Fixed abstract section tag. Fixed figure tags to conform to simple docbook
+Modified Files:
+ Tag: ALPHA-0_7
+ listener-module.xml
+
+Revision 1.1.2.2 2003/03/10 23:43:32 akarasulu
+Moved links so that image references point to /image/design. Note that
+references do not have a [.] in front since the maven driven transforms
+automatically append [.] to references.
+
+Revision 1.1.2.1 2003/03/10 23:24:21 akarasulu
+Moved design documentation from docs/design to src/docbook/design.
+
+Revision 1.1.2.1 2003/03/09 22:14:08 akarasulu
+moved the listner.xml file to listener-module.xml
+
+Revision 1.1.2.4 2003/03/02 02:14:51 akarasulu
+Added sequence diagram for the listener thread loop.
+
+Revision 1.1.2.3 2003/03/02 00:37:31 akarasulu
+Adjusting spacing.
+
+Revision 1.1.2.2 2003/03/02 00:32:39 akarasulu
+Completed listener documentation but needs some work and added the article
+info tag to both these document. Also flaged these docs as whitepapers.
+
+ </para>
+ </revdescription>
+ </revision>
+ </revhistory>
+ </articleinfo>
+
+ <abstract>
+ <para>
+ The listener module is responsible for accepting client connections
+ on a tcp port of an ip interface. In this sense it listens for
+ client connections. The module implements the ServerListener interface.
+ </para>
+ </abstract>
+
+ <section>
+ <title>Document TODOs:</title>
+ <itemizedlist>
+ <listitem><para>
+ Add links to other documents refered to
+ </para></listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Implementation</title>
+
+ <para>
+ Currently the ListenerModule only supports a single server socket
+ connection and does not presently support SSL. It is a blocking
+ implementation requiring a blocked thread on the accept() method
+ of the ServerSocket.
+ </para>
+
+ <para>
+ The module is not a stage yet it is not a simple module as defined
+ in the architecture document. The module is a Runnable module that
+ uses a single thread to detect client connections on the server
+ socket. This thread runs until the Module is stopped. The module
+ starts the listener thread in the start stage of the module. The
+ thread is created fresh and started - it is not claimed from a pool.
+ </para>
+
+ <figure>
+ <title>Listener Thread Loop Sequence Diagram</title>
+ <graphic fileref="../images/ListenerModuleRun.gif"/>
+ </figure>
+
+ <para>
+ Once started the module's driving thread enters a while loop that
+ completes when the hasStarted() status returns false for the module.
+ A call to stop() will statisfy this stop condition. Upon entering
+ the while loop the thread blocks on the ServerSocket's accept()
+ method until a client connection is made. accept() returns with a
+ client Socket which is packaged into a brand new ConnectEvent. The
+ ConnectEvent is a special ClientManager specific event. It is a
+ SEDA event. Once the ListenerModule creates the ConnectEvent with
+ the Socket inside, a call is made to the ClientManager service's
+ connectPerformed() method with the event as the sole argument. Once
+ this call completes the thread starts the loop over again providing
+ the module has not been stopped. It is very important to make sure
+ that ClientManager implementations do not spend too much time
+ handling the event. The ClientModule which implements the
+ ClientManager service interface for this reason is implemented as a
+ stage. The idea here is that the cost of the connectPerformed
+ event handling operation is merely translated into a SEDA stage
+ enqueue. The processing is handled later asynchronously by a
+ ClientModule worker thread. More details are available in the SEDA
+ Stage implementation document. The use of a stage for the
+ ClientModule makes connection handling instantaneous allowing the
+ listener thread to immediately return to listening on the port for
+ new clients. The inability to quickly complete a loop upon an
+ accept() return would translate into connection latencies when the
+ client connection frequency is high.
+ </para>
+ </section>
+
+ <section>
+ <title>Future</title>
+
+ <para>
+ This module is very primitive and will see several changes as the
+ server matures and is optimized. At this point we see obvious
+ changes that merely add features. At some point before a beta the
+ module will need to support listening for client connections on
+ multiple ports and ip interfaces. It must also enable the use of
+ SSL while handling the nuiances to accomodate the StartTLS extended
+ request implementation.
+ </para>
+
+ <para>
+ Beta releases will optimize the server for various JDK platforms.
+ There is very little that can be done to optimize the module for the
+ JDK1.3 and lesser platforms however this is not the case for JDK1.4.
+ By using selectable channels we can use a single thread to listen
+ for client connections on any number of ports and ip interfaces
+ rather than allocating a thread for each tcp port. This provides
+ better scalability for the server as the number of ports it listens
+ to increase. At the end of the day however just how many ports do
+ we expect an LDAP server to be listening to. So optimization would
+ almost be moot. Regardless if a commital to optimizing the module
+ is made for the JDK1.4 then a JDK based swapping schema must be
+ used to switch the implementation. To have a single code base run
+ on both the JDK1.4 and be compatible for lesser versions, we must
+ swap selectable new IO channels for simple io at server
+ initialization time when the JDK version can be queried from the
+ system properties.
+ </para>
+ </section>
+</article>
Added: incubator/directory/eve/branches/start/src/docbook/design/module-implementation-template.xml
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/docbook/design/module-implementation-template.xml Thu Jun 24 00:06:35 2004
@@ -0,0 +1,86 @@
+<?xml version="1.0"?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD Simplified DocBook XML V4.1.2.5//EN"
+ "http://www.oasis-open.org/docbook/xml/simple/4.1.2.5/sdocbook.dtd">
+
+<article class="whitepaper">
+ <title>Module Implementation</title>
+
+ <articleinfo>
+ <author><othername>akarasulu</othername></author>
+ <editor><othername>$Author: bearcej $</othername></editor>
+ <revhistory>
+ <revision>
+ <revnumber>$Revision: 1.3 $</revnumber>
+ <date>$Date: 2003/05/03 01:21:32 $</date>
+ <revdescription>
+ <para>
+$Log: module-implementation-template.xml,v $
+Revision 1.3 2003/05/03 01:21:32 bearcej
+Remove tabs from doc files and fix linefeeds.
+
+Revision 1.2 2003/03/23 13:24:46 akarasulu
+Added these files from the ALPHA-0_7 branch.
+
+Revision 1.1.2.1 2003/03/10 23:24:21 akarasulu
+Moved design documentation from docs/design to src/docbook/design.
+
+Revision 1.1.2.1 2003/03/03 04:49:25 akarasulu
+Added as placeholders for now.
+
+ </para>
+ </revdescription>
+ </revision>
+ </revhistory>
+ </articleinfo>
+
+ <abstract>
+ <para>
+ </para>
+ </abstract>
+
+ <section>
+ <title>Document TODOs:</title>
+ <itemizedlist>
+ <listitem><para>
+ Add diagrams.
+ </para></listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Implementation</title>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+ </section>
+
+ <section>
+ <title>Future</title>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+ </section>
+
+ <section>
+ <title>Faults</title>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+ </section>
+
+</article>
Added: incubator/directory/eve/branches/start/src/docbook/design/nexus-module.xml
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/docbook/design/nexus-module.xml Thu Jun 24 00:06:35 2004
@@ -0,0 +1,298 @@
+<?xml version="1.0"?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD Simplified DocBook XML V4.1.2.5//EN"
+ "http://www.oasis-open.org/docbook/xml/simple/4.1.2.5/sdocbook.dtd">
+
+<article class="whitepaper">
+ <title>Module Implementation</title>
+
+ <articleinfo>
+ <author><othername>akarasulu</othername></author>
+ <editor><othername>$Author: bearcej $</othername></editor>
+ <revhistory>
+ <revision>
+ <revnumber>$Revision: 1.6 $</revnumber>
+ <date>$Date: 2003/05/03 01:45:23 $</date>
+ <revdescription>
+ <para>
+$Log: nexus-module.xml,v $
+Revision 1.6 2003/05/03 01:45:23 bearcej
+Refix image URLs
+
+Revision 1.5 2003/05/03 01:43:08 bearcej
+Add maven file to help generate server site.
+Modify graphic links again.
+Remove tabs from doc files and fix linefeeds.
+
+Revision 1.4 2003/05/03 01:21:32 bearcej
+Remove tabs from doc files and fix linefeeds.
+
+Revision 1.3 2003/04/08 02:29:55 bearcej
+* Clean up project.properties
+* Fix logos in project.xml
+* Fix links to image files in docs
+
+Revision 1.2 2003/03/23 13:24:46 akarasulu
+Added these files from the ALPHA-0_7 branch.
+
+Revision 1.1.2.3 2003/03/15 17:19:44 bearcej
+Fixed figure tags to confirm to simple docbook.
+Modified Files:
+ Tag: ALPHA-0_7
+ nexus-module.xml
+
+Revision 1.1.2.2 2003/03/10 23:43:32 akarasulu
+Moved links so that image references point to /image/design. Note that
+references do not have a [.] in front since the maven driven transforms
+automatically append [.] to references.
+
+Revision 1.1.2.1 2003/03/10 23:24:21 akarasulu
+Moved design documentation from docs/design to src/docbook/design.
+
+Revision 1.1.2.2 2003/03/10 21:44:14 akarasulu
+Done with nexus module documentation
+
+Revision 1.1.2.1 2003/03/03 04:49:25 akarasulu
+Added as placeholders for now.
+
+ </para>
+ </revdescription>
+ </revision>
+ </revhistory>
+ </articleinfo>
+
+ <abstract>
+ <para>
+ The NexusModule implements the UnifiedBackend service and was
+ intended as a Backend hub or nexus for glueing together multiple
+ naming contexts into one unified system while centralizing the
+ management of operational attributes. The module routes Create,
+ Read, Update and Delete (CRUD) method calls on entries as well
+ as Directory Information Base (DIB) management operations to owning
+ Backends. As a wrapper around all server Backends it has the unique
+ opportunity to centralize the maintanance of operational attributes
+ for all entries before and after entry CRUD method calls and DIB
+ management operations.
+ </para>
+ </abstract>
+
+ <section>
+ <title>Document TODOs:</title>
+ <itemizedlist>
+ <listitem><para>
+ Add diagrams.
+ </para></listitem>
+ </itemizedlist>
+ </section>
+
+
+ <section>
+ <title>Architecture</title>
+
+ <para>
+ Breifly stated, the architectural goal is to have one central
+ naming context independent service responsible for all Directory
+ Information Base (DIB) operations. Centralized DIB managment
+ enables the transparent introduction of operational attributes in
+ a standard manner independent of context assigned Backends. Backend
+ implementations need not manage operational attributes other than
+ those specific to and required by their implementations. Backend
+ implementation operational attribute maintenance overheads,
+ complexity and coupling to other server modules decrease when a
+ centralized unified backend nexus service is introduced.
+ </para>
+
+ <para>
+ The org.apache.eve.backend package within the ldapd-server subproject
+ defines three critical interfaces to enable the aforementioned
+ architectural goals. The core Backend interface declares the
+ signatures of entry CRUD operations as well as other DIB management
+ operations. The interface does not define a ROLE constant. The
+ primary purpose of the Backend interface is structural:
+ implementations of this interface are not expected. The lack of a
+ ROLE constant revieals our intention: the Backend interface alone
+ is insufficient for a viable backend service. See Figure I below:
+ </para>
+
+ <figure>
+ <title>Figure I: Backend Interfaces</title>
+ <graphic fileref="../images/BackendInterfaces.gif"/>
+ </figure>
+
+ <para>
+ Two service interfaces are defined with a ROLE constant member:
+ UnifiedBackend and AtomicBackend. Implementations of these
+ interfaces would constitute a viable service. Both service
+ interfaces extend from the Backend base interface. Extention from
+ Backend implies the ability of both sub interfaces to handle entry
+ CRUD operations and DIB management operations. These relationships
+ are depicted in the UML diagram above.
+ </para>
+
+ <para>
+ The AtomicBackend service interface declares additional methods
+ required by concrete backends assigned as the backing store to one
+ and only one naming context. Context specificity is implied by
+ the getSuffix() method declaration in AtomicBackend. Extention of
+ the BackendConfig interface by the AtomicBackend further
+ differntiates it from the UnifiedBackend by introducing backend
+ configuration parameter management interfaces. As its name
+ suggests, the AtomicBackend is clearly designed to implement an
+ indivisible backend for a single naming context specified by a
+ distinguished name suffix. For more information see the <ulink
+ url="backend-module.html">BackendModule</ulink> documentation.
+ </para>
+
+ <para>
+ The UnifiedBackend service interface contains methods that
+ differentiates its role from the AtomicBackend interface. These
+ methods lookup, register, unregister and list AtomicBackends and
+ the suffixes of their naming contexts. The registration methods
+ of the interface allow the addition and removal of AtomicBackends
+ from the nexus service. The service enables lookups of currently
+ registered AtomicBackends through the getBackend() method which
+ looksup AtomicBackends by suffix distinuished names. Registered
+ AtomicBackends or their suffixes are listed using the listBackends()
+ and listSuffixes() methods. The interface also contains naming
+ context independent methods. An example would be the getRootDSE()
+ method, which returns the Root Directory Server Agent (DSA) Entry
+ or RootDSE. The RootDSE resides at a nameless context and is looked
+ up using a one level search with an empty search base distinguished
+ name. The unified backend is the best location for context indepent
+ entries like the RootDSE.
+ </para>
+
+ <para>
+ Other utility methods on the UnifiedBackend provide a convenient
+ means to parse distinguished names as Strings into javax.naming.Name
+ object instances or to get a valid parser for a specific DN. These
+ methods help present a facade to schema driven distinguished name
+ parsering. They remove the need for modules upstream of the nexus
+ to have to interface with the SchemaManager. The nexus hence acts
+ like a one stop service for modules like the ProtocolModule.
+ </para>
+ </section>
+
+
+ <section>
+ <title>Implementation</title>
+
+ <para>
+ The NexusModule implements the UnifiedBackend interface and extends
+ the AbstractModule base class. The Backend interface method
+ implementations merely wrap calls to underlying AtomicBackends after
+ resolving a distinguished name to the owning AtomicBackend. All
+ Backend methods provide some manner of access to a distinguished
+ name which localizes the operation within a specific naming context.
+ The distinguished name is either provided as an argument or can be
+ accessed from an argument passed into the method. If the resolution
+ of a distinguished name to a registered AtomicBackend fails, the
+ method throws the appropriate subtype of NamingException. For these
+ reasons and others virtually all Backend interface methods throw the
+ NamingException superclass.
+ </para>
+
+ <para>
+ Perhaps the most significant method implementations for the module
+ are those that resolve a distinguished name to a naming context,
+ enable search traps for returning the RootDSE and configure the
+ module. Each of these method implementations are described in the
+ paragraphs below.
+ </para>
+
+ <para>
+ The getBackend() method resolves a distinguished name provided as a
+ javax.naming.Name argument into a naming context and returns the
+ AtomicBackend associated with the context. The NexusModule keeps a
+ Map of suffix distinguished names mapped as java.lang.Sting keys to
+ AtomicBackend instances. To lookup and return the AtomicBackend the
+ backend suffix must be extracted from Name argument. First before
+ considerable investment, the method checks to see if the argument
+ represents a suffix. Next it presumes the Name argument represents
+ a non-suffix entry and cycles through all contexts looking for the
+ one whose suffix is a prefix to the Name argument. If the loop
+ does not find a valid AtomicBackend, an IllegalArgumentException
+ is thrown. Otherwise the AtomicBackend is returned.
+ </para>
+
+ <para>
+ Without traping search requests, a RootDSE search would result in
+ an IllegalArgumentException in getBackend() due to the empty String
+ provided as the search base. Remember to list the contents of the
+ RootDSE the search base must be set to the empty string. The nexus
+ inspects every search request to see if it needs to bypass normal
+ search processing. Normally the nexus would forward the search
+ request to the appropriate backend resolved using the search base.
+ Upon detection of a search with base scope and an empty string for
+ the search base, the nexus bypasses normal search processing. It
+ creates a special Cursor which returns only one entry: the RootDSE.
+ </para>
+
+ <para>
+ The configuration of the module simply extracts the attributes of
+ the RootDSE from the config.xml. The attributes are stored in XML
+ using <attribute> tags having two manditory attributes: "name"
+ and "value". The name attribute is used as the id of the LDAP
+ attribute to add to the RootDSE. The value attribute is obviously
+ used as the value of the named LDAP attribute. These attributes are
+ used to build the RootDSE entry on the spot. The RootDSE is a
+ special implementation of LdapEntry specifically for this purpose.
+ </para>
+ </section>
+
+ <section>
+ <title>Future</title>
+
+ <para>
+ Enable automatic updates to the RootDSE whenever new naming contexts
+ are created or destroyed with the registration and unregistration of
+ AtomicBackends. The namingContexts attributes would be added and
+ removed when Backends are registered and unregistered respectively.
+ </para>
+
+ <para>
+ Enable administrative naming contexts for cn=schema and other
+ administrative areas.
+ </para>
+
+ <para>
+ Start managing critical operational attributes defined in RFC2251
+ for the creators name, creation timestamp or the modifiers name etc.
+ </para>
+ </section>
+
+ <section>
+ <title>Faults</title>
+
+ <para>
+ Does not manage operational attributes.
+ </para>
+
+ <para>
+ We need to reinvestigate the service interfaces implemented by this
+ module as well as AtomicBackends to find a better more JNDI like
+ mechanism for operating against a DIB. These new interfaces should
+ make the JNDI provider implementation trivial if designed correctly.
+ Currently, serveral transformations of an LdapEntry to an Attributes
+ object in the JNDI provider impose inefficiencies and extra code in
+ the provider. By reducing the rift between the Backend super
+ interface and the JNDI API methods these inefficiencies can be
+ avoided while reducing the code base. As a pleasent side effect,
+ upstream dependent modules can use the JNDI provider rather than
+ access the nexus directly. This would make those dependant modules
+ easier to understand since JNDI APIs are standard JDK APIs more
+ familiar to most developers than the Backend, AtomicBackend, and
+ UnifiedBackend interfaces as they exist today. Another major
+ benefit gained from the use of the internal server side JNDI
+ provider would be entry location transparency. If JNDI is used
+ references can be automatically resolved by the provider based on
+ the controls in effect. The protocol module would not have to
+ directly invoke the Sun LDAP JNDI provider to resolve references on
+ behalf of the user. The server-side provider would handle
+ references in a manner consistant with the controls bound to the
+ ClientSession. The protocol module would just use JNDI would little
+ regard concerning the nature of the entries returned. The use of
+ the server-side JNDI provider would hence greatly simplify the
+ implementation of the ProtocolEngine.
+ </para>
+ </section>
+</article>
Added: incubator/directory/eve/branches/start/src/docbook/design/operations/opertion-template.xml
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/docbook/design/operations/opertion-template.xml Thu Jun 24 00:06:35 2004
@@ -0,0 +1,106 @@
+<?xml version="1.0"?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD Simplified DocBook XML V4.1.2.5//EN"
+ "http://www.oasis-open.org/docbook/xml/simple/4.1.2.5/sdocbook.dtd">
+
+<article class="whitepaper">
+ <title>LDAPv3 Protocol Operation Design And Implementation</title>
+
+ <articleinfo>
+ <author><othername>akarasulu</othername></author>
+ <editor><othername>$Author: bearcej $</othername></editor>
+ <revhistory>
+ <revision>
+ <revnumber>$Revision: 1.2 $</revnumber>
+ <date>$Date: 2003/05/03 01:21:33 $</date>
+ <revdescription>
+ <para>
+$Log: opertion-template.xml,v $
+Revision 1.2 2003/05/03 01:21:33 bearcej
+Remove tabs from doc files and fix linefeeds.
+
+Revision 1.1 2003/03/28 05:12:35 akarasulu
+Adding documents to track changes to protocol enhancements.
+
+ </para>
+ </revdescription>
+ </revision>
+ </revhistory>
+ </articleinfo>
+
+ <abstract>
+ <para>
+ </para>
+ </abstract>
+
+ <section>
+ <title>Document TODOs:</title>
+ <itemizedlist>
+ <listitem><para>
+ Add diagrams.
+ </para></listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Comments on Protocol Requirements</title>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+ </section>
+
+ <section>
+ <title>Design</title>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+ </section>
+
+ <section>
+ <title>Implementation</title>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+ </section>
+
+ <section>
+ <title>Future</title>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+ </section>
+
+ <section>
+ <title>Faults</title>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+ </section>
+
+</article>
Added: incubator/directory/eve/branches/start/src/docbook/design/operations/search-operation.xml
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/docbook/design/operations/search-operation.xml Thu Jun 24 00:06:35 2004
@@ -0,0 +1,745 @@
+<?xml version="1.0"?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD Simplified DocBook XML V4.1.2.5//EN"
+ "http://www.oasis-open.org/docbook/xml/simple/4.1.2.5/sdocbook.dtd">
+
+<article class="whitepaper">
+ <title>LDAPv3 Search Operation Design And Implementation</title>
+
+ <articleinfo>
+ <author><othername>akarasulu</othername></author>
+ <editor><othername>$Author: bearcej $</othername></editor>
+ <revhistory>
+ <revision>
+ <revnumber>$Revision: 1.7 $</revnumber>
+ <date>$Date: 2003/05/03 01:21:33 $</date>
+ <revdescription>
+ <para>
+$Log: search-operation.xml,v $
+Revision 1.7 2003/05/03 01:21:33 bearcej
+Remove tabs from doc files and fix linefeeds.
+
+Revision 1.6 2003/04/04 01:40:16 akarasulu
+Added more to search operation document yet temporarily suspended it to
+start working on request scope management design which all operations will
+eventually depend upon.
+
+Revision 1.5 2003/04/02 22:15:00 akarasulu
+Added section on jdbm backend design for alias dereferencing.
+
+Revision 1.4 2003/04/02 16:23:39 akarasulu
+Exploring issues dealing with alias cycles, indirect alias chains and how
+they must be handled.
+
+Revision 1.3 2003/04/02 02:15:24 akarasulu
+Got down to how we should finally handle alias dereferencing modes.
+
+Revision 1.2 2003/03/31 13:14:12 akarasulu
+Added more documentation on alias dereferencing.
+
+Revision 1.1 2003/03/28 05:12:35 akarasulu
+Adding documents to track changes to protocol enhancements.
+
+ </para>
+ </revdescription>
+ </revision>
+ </revhistory>
+ </articleinfo>
+
+ <abstract>
+ <para>
+ </para>
+ </abstract>
+
+ <section>
+ <title>Document TODOs:</title>
+ <itemizedlist>
+ <listitem><para>
+ Add diagrams.
+ </para></listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Comments on Protocol Requirements</title>
+
+ <section>
+ <title>Aliases and Search Operations</title>
+
+ <para>
+ Alias entries according to X.501 are entries "of the class
+ 'alias' containing information used to provide an alternative
+ name for an object." The objectClass definition for an alias
+ is provided below along with the attributeType definition for
+ its sole required attribute aliasedObjectName:
+ </para>
+
+ <programlisting>
+ objectclass ( 2.5.6.1 NAME 'alias' SUP top STRUCTURAL
+ MUST aliasedObjectName )
+
+ attributetype ( 2.5.4.1 NAME 'aliasedObjectName'
+ EQUALITY distinguishedNameMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE )
+ </programlisting>
+
+ <para>
+ The aliasedObjectName is uses the distinguishedNameSyntax.
+ Aliases can only refer to entries local to the DSA since they
+ only represent distinguished names and not an LDAP URL. There
+ seems to be no documentation pertaining to the use of aliases
+ that span across DIBs. Hence we presume an alias in one backend
+ can refer to an entry within another. Aliases cannot refer to
+ other aliases in an alias chain according to X.501. Write
+ operations are not allowed to affect the DIT through aliases
+ (need confirmation about this). There seems to be a defunct
+ IETF draft that never made it to RFC which discusses the
+ expected behavoir of aliases. See <ulink url=
+"http://www.globecom.net/ietf/draft/draft-byrne-ldap-alias-00.html">
+ draft-byrne-ldap-alias-00 </ulink> for more information
+ regarding alias behavior in LDAPv3. While reading this draft
+ note that it often violates RFC 2251 - namely by allowing
+ aliases to other aliases in a chain.
+ </para>
+
+ <para>
+ According to X.511 section 12.5.2.1 the following error codes
+ are associated with aliases (see <ulink url=
+"http://www.alternic.org/drafts/drafts-j-k/draft-just-ldapv3-rescodes-02.txt">
+ Error Code Definitons Draft</ulink> for detailed error code
+ explanations):
+ </para>
+
+ <table frame='all'><title>Mandarory LDAPd Services</title>
+ <tgroup cols='3' align='left' colsep='1' rowsep='1'>
+ <colspec colname='ErrorName'/>
+ <colspec colname='LDAPv3Code'/>
+ <colspec colname='Description'/>
+ <thead>
+ <row>
+ <entry>Error Name</entry>
+ <entry>LDAPv3 Code</entry>
+ <entry>Error Condition Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>aliasProblem</entry>
+ <entry>33</entry>
+ <entry>An alias has been dereferenced which names
+ no object - a broken link where destination
+ entry does not exist. [X511, Section 12.5].
+ </entry>
+ </row>
+ <row>
+ <entry>aliasDereferencingProblem</entry>
+ <entry>36</entry>
+ <entry>An alias was encountered in a situation where
+ it was not allowed. For example an add that
+ creates an alias to another alias could throw
+ this error or a delete operation going through
+ an alias. If the client does not have read
+ permission for the aliasedObjectName attribute
+ and its value then the error should be returned.
+ [X511, Section 7.11.1.1]
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>
+ According to section 4.5.1 of RFC
+ <ulink url="http://www.faqs.org/rfcs/rfc2251.html">2251</ulink>,
+ search requests contain a search operation modifier called
+ derefAliases which affect the manner in which aliases are
+ handled during the course of a search operation. Parts of the
+ RFC's section defining the values of the derefAliases search
+ parameter are listed in the block below:
+ </para>
+
+ <programlisting>
+
+ Search Request ASN.1 Notation Snippet:
+ --------------------------------------
+
+ derefAliases ENUMERATED {
+ neverDerefAliases (0),
+ derefInSearching (1),
+ derefFindingBaseObj (2),
+ derefAlways (3) }
+
+ Indicator Commentary Snippet:
+ -----------------------------
+
+ derefAliases: An indicator as to how alias objects (as defined in
+ X.501) are to be handled in searching. The semantics of the
+ possible values of this field are:
+
+ neverDerefAliases: do not dereference aliases in searching
+ or in locating the base object of the search;
+
+ derefInSearching: dereference aliases in subordinates of
+ the base object in searching, but not in locating the
+ base object of the search;
+
+ derefFindingBaseObj: dereference aliases in locating
+ the base object of the search, but not when searching
+ subordinates of the base object;
+
+ derefAlways: dereference aliases both in searching and in
+ locating the base object of the search.
+
+ </programlisting>
+
+ <para>
+ The definitions for the four modes of alias handling raise
+ questions regarding alias handling behavoir. These questions
+ deal with the order in which dereferencing and search selection
+ criteria are applied. If alias dereferencing is applied before
+ the application of search criteria then the filter takes affect
+ on the target entry referred to by the alias. Conversely if
+ dereferencing is applied after the application of search
+ criteria then the filter is applied to the alias itself and not
+ on the target entry. In the later case the alias may never be
+ a candidate for dereferencing if the search filter does not
+ select it. Although a subtle nuance in alias handling, the
+ order of handling can produce dramatic differences in the
+ returned search result set.
+ </para>
+
+ <para>
+ These questions must be answered before choosing a design
+ approach that incorporates the handling of aliases. The
+ existing LDAP and DAP standards do not explicitly confront these
+ crutial details. Perhaps the lack of standardization is the
+ reason why so many directory servers do not support aliases.
+ The SUN One Directory Server for example does not support
+ aliases at all. Although a sticky point aliases provide
+ an immeasurable degree of flexibility, and should be supported.
+ Ultimately we need to pose these questions to both the LDAP and
+ DAP communities to find the appropriate answers. For the time
+ being some inferences can be drawn from what little information
+ we do have regarding alias handling. These inferences can be
+ presented to the community for definitive answers after we draw
+ them out below.
+ </para>
+
+ <para>
+ Let's consider alias handling for searches when the search base
+ is an alias. In neverDerefAliases or in derefInSearching modes
+ the search base is never dereferenced. Hence it must be treated
+ like any other regular leaf entry. Depending on the search
+ scope and the filter used there are two possible outcomes:
+ either nothing is returned or the search base entry (the alias)
+ is returned. Regardless of the filter used, a search scope set
+ to one level search will always return nothing. One level
+ scoped searches never return the search base entry in the result
+ set. If base level or subtree level search scope is used, then
+ the alias is returned in the result set only if the search
+ filter selects the base (alias) entry. For example a filter of
+ '(objectClass=alias)' will select the alias entry when the
+ search scope is set to the base or subtree level scope. If the
+ alias entry is to be returned it is packaged in a
+ SearchResultEntry PDU and sent to the client. A final
+ SearchResultDone PDU signals the completion of the search
+ operation. If the alias is not selected a single
+ SearchResultDone PDU only.
+ </para>
+
+ <para>
+ If a search request has derefAliases set to derefAlways or
+ derefFindingBaseObj then the search base if it is an alias is
+ dereferenced before the search filter is applied. The effective
+ search base then becomes the DN of the entry pointed to by the
+ alias. In these cases alias, dereferencing of the base must be
+ applied before the search begins. Use of the aliased DN
+ propagates it to the new search base. Ironically the previous
+ filter example '(objectClass=alias)' using the base search scope
+ should return nothing in these modes which do dereference the
+ base entry. The reason being is the dereferenced base cannot
+ be an alias since chaining is not allowed. So once the new base
+ is dereferenced, and the filter is applied, the filter
+ expression will not select it. Based on the position of the
+ new search base, the search scope, and the search filter the
+ returned result set could be just about anything. We can only
+ comment on this one special filter example's result.
+ </para>
+
+ <para>
+ Search behavoir under these cases enabling search base
+ dereferencing are well understood and documented. It is clear
+ in these cases that dereferencing of aliases must occur before
+ the application of search filters to select dereferenced entries
+ and their descendants. Standards however lack clarity with
+ regard to search behavoir when alias dereferencing is totally
+ enabled while searching. To obtain a solid footing we have
+ decided to take a leap of faith with a simple presumption
+ regarding alias handling consistancy. The presumption stems
+ from our clear conclusions regarding the order of dereferencing
+ found for alias handling on search bases. In this light, we
+ presume the consistant application of alias dereferencing
+ before the application of search criteria across all alias
+ handling modes. So with this premis, derefInSearching mode on
+ a subtree scoped search would dereference every descendant
+ alias under the search base whether or not the search filter
+ selects descendant alias entries. The impact of this premis
+ aligns perfectly well with search semantics and the concept of
+ name aliases. Aliases alter both the DIT structure and the
+ namespace by providing alternative names for entries. In
+ affect, under the various modes of alias handling they present
+ different views of the DIT to search operations. When aliases
+ are never dereferenced the DIT remains a perfect tree structure
+ with aliases represented as leaf entries. Without
+ dereferencing, aliases have no influence on the effective
+ namespace presented to a search operation. When alias
+ dereferencing is totally enabled, the effective DIT structure
+ and namespace, which a search filter operates on, differs from
+ modes where alias dereferencing is totally disabled. The
+ alternative view of the DIT structure and namespace represents
+ aliased names and alias induced structural relationships as
+ actual entry names and relationships as if aliases never
+ existed in the first place. The new modifed view of the DIT,
+ depending on the aliases used, may be a tree or it may be a
+ graph. Regardless the search algorthim which applies the filter
+ to the DIB, should operate on the modified view when alias
+ dereferencing has been totally enabled.
+ </para>
+
+ <para>
+ In conclusion, all alias handling modes, if at all, must
+ dereference aliases before applying search filters to select
+ DIT entries. This clarifies our approach in dealing with the
+ two modes: derefInSearching and derefAlways. derefAlways after
+ the initial search base is dereferenced reduces to the
+ derefInSearching mode by using the DN of entry referenced by the
+ alias. After this step the handling of these modes are the
+ same. To conduct searches in derefAlways and derefInSearching
+ modes the alias dereferencing mechanism is unfortunately
+ optimally implemented within a backend module's search algorthm
+ to enable dereferencing before the application of search
+ criteria. This is unfortunate because it demands the knowledge
+ of alias handling behavoir on the part of backends and their
+ implementors.
+ </para>
+
+ <para>
+ Another potential pitfall while dereferencing aliases during
+ searches with subtree scope appears when aliases induce cycles
+ within the DIT. Cycles cause infinite loops or the return
+ of redundant entry copies to the client. A simple cycle
+ results when an alias refers back to a relative within the
+ heirarchy. Dereferencing the alias to propagate the search back
+ at the relative eventually encounters the alias once again and
+ so on in an infinite search loop. One approach to mitigate the
+ problem would be to restrict alias creation, by rejecting the
+ addition of aliases to the DIT which cause cycles where the
+ offending alias refers back to an immediate or distant parent.
+ Another approach would be to track search propagation preventing
+ the dereferencing of aliases more than once. Although the
+ approach prevents an infinite loop it does not prevent the
+ possibility of returning duplicate entry copies to the client.
+ The search would have to track the entries it has already
+ returned to prevent the redundant return of duplicates.
+ </para>
+
+ <para>
+ More complex situations occur where indirect alias chains cause
+ cycles. When refering to indirect chains we do not mean the
+ referral of one alias to another. This is not allowed to begin
+ with. Indirect chains occur when one alias refers to an entry,
+ which has a descendant alias that refers back to a parent of the
+ first alias. Under a subtree scoped search with dereferencing
+ enabled, the search would eventually cycle from the first alias
+ to the second and back to the first. This "indirect chain"
+ presents the same challanges encountered in a simple cyclic
+ alias. The chain however is much harder to detect and its
+ affects are less trivial to handle than the simple cycle
+ inducing alias. These problems must be confronted regardless
+ of the design approach.
+ </para>
+
+ <para>
+ With respect to JNDI, alias dereferencing is controled using the
+ "java.naming.ldap.derefAliases" environment property. The
+ "dereference links" flag obtained via the getDerefLinkFlag() on
+ SearchControls has nothing to do with alias dereferencing.
+ This is clearly stated in the tutorial for JNDI. However, the
+ flag's purpose is unknown due to lack of documentation by SUN.
+ Can someone find out what it's used for? Also when resolving
+ the name of an aliased entry using the NameClassPair method
+ getName() on dereferenced aliases, the name returned will be the
+ full distinguished name of the aliased entry and not the
+ relative distinguished name. As a consequence the isRelative()
+ method for the NameClassPair should return false. This nuance
+ yet a requirement of JNDI must be meet by the server side JNDI
+ provider once alias dereferencing is enabled.
+ </para>
+ </section>
+ </section>
+
+ <section>
+ <title>Design</title>
+
+ <section>
+ <title>Alias Handling in Search Operations</title>
+
+ <para>
+ With some of our conclusions in the protocol commentary section
+ above regarding alias handling, we now consider some design
+ approaches in this section. These approaches are dependent on
+ the existing server design and so we breifly recap its relavent
+ aspects.
+ </para>
+
+ <para>
+ The search operation is conducted within the ProtocolModule
+ using a search request processor. The processor extracts search
+ parameters from the SearchRequest PDU and calls the search
+ method on the nexus to return a Cursor over the result set. The
+ processor then enters a loop to pull entries one at a time from
+ the backend using the search Cursor. Each iteration transmits
+ an entry packaged within a SearchResultEntry PDU to the client.
+ The Cursor returned by the search method of the nexus, is
+ actually created by calling the search method on the backend
+ associated with the naming context of the search base. In this
+ respect the nexus design presumes the confinement of a search
+ operation to a single backend. The current nexus design
+ presents challanges for alias dereferencing when aliases in one
+ backend refer to entries in other backends. "DIB crossing
+ aliases", as we coin them, may require a completely different
+ approach to handling dereferencing.
+ </para>
+
+ <para>
+ With the design in mind we now explore the design options
+ for the various alias dereferencing modes. Without alias
+ dereferencing support the server effectively operates in
+ neverDerefAliases mode. The alias is returned itself within a
+ SearchResultEntry PDU as if it is a terminal leaf entry.
+ derefFindingBaseObj mode could be handled trivially before
+ calling search on the nexus within the search processor. Search
+ base dereferencing can also be handled within the nexus itself.
+ In these cases, the search base entry could be checked to see
+ if it is an alias. If it is an alias the target entry it points
+ to could be dereferenced and used as the base of the search when
+ the call to the nexus or owning backend is made. The amount of
+ change required to enable this mode is trivial with several
+ implementation alternatives.
+ </para>
+
+ <para>
+ The other two modes, derefInSearching and derefAlways, would
+ require non-trivial changes to handle alias dereferencing since
+ they pervade into the searching mechanism. Requirin the
+ dereferencing of aliases before the application of search
+ selection criteria, tightly couples dereferencing with the
+ search algorithm. In an effort to simplify our approach, we
+ reduce the two modes into one. As mentioned before the only
+ difference between derefInSearching and derefAlways modes is
+ the fact that the search base if it is an alias is resolved
+ before the search. So for all practical purposes we can reduce
+ the derefAlways mode into the derefInSearching mode by
+ dereferencing the search base to the aliased DN. Then the
+ dereferenced entry can then be used as the search base while
+ conducting the search as if it were in derefInSearching mode.
+ Even with this reduction, derefInSearching mode is not a simple
+ mode to manage especially with whole subtree scoped searches.
+ Many approaches can be taken for dereferencing aliases when in
+ derefInSearching mode. We shall explore the options within the
+ rest of this section to determine the most optimal design for
+ searches conducted in derefInSearching mode. All options below
+ are geared specifically to the toughest case to handle: a
+ search in derefInSearching mode with the scope set to the whole
+ subtree.
+ </para>
+
+ <section>
+ <title>Alias Handling Outside of Backends</title>
+
+ <para>
+ Already congested Backends can be spared by embedding alias
+ dereferencing fuctionality into the protocol engine's search
+ request processor or into the nexus module. While iterating
+ through the resultant cursor the search processor may encounter
+ aliased entries. On an alias entry the processor can conduct a
+ subordinate search using the DN of the aliased entry as the
+ search base with the parent search's parameters. Once a
+ subordinate search cursor is consumed the parent search can
+ carry on from where it left off.
+ </para>
+
+ <para>
+ This approach has several problems. The the most apparent lies
+ in the fact that a subordinate search may return yet another
+ alias and its subordinates may in turn return more aliases and
+ so on. A recursive solution would be required to resolve the
+ possible heirarchy of alias triggered subordinate searches. A
+ special cursor can be designed to encapsulate the process and
+ lessen the amount of impact this would produce on the regions
+ responsible for alias dereferencing. At some point during the
+ search the number of subordinate search cursors waiting for the
+ last cursor in the chain to complete will be equal to the depth
+ of the deepest alias chain in the search. That is if there are
+ no time or size limitations. Furthermore there is the danger
+ of cyclic aliases mentioned before. To prevent such situations
+ the search must maintain a common cache of entries that it has
+ already returned. The cache must be shared by all subordinate
+ search cursors. Alias dereferencing functionality implemented
+ outside of the backend need not be pushed into the processor -
+ it could reside in the nexus (a.k.a. the UnifiedBackend).
+ Regardless of where it is located, if it does not reside within
+ backends, it will have the same set of challanges to confront.
+ These challanges will require recursive solutions.
+ </para>
+
+ <para>
+ This approach is certainly not trivial however it does spare
+ backends from having to manage aliases. If aliases were
+ managed by backends then they would have to manage them for all
+ protocol operations. Each backend would have to apply its own
+ unique means to accomplish this depending on the nature of its
+ backing store and hence its own design. We explore these issues
+ with regard to the JDBM backend in the section to follow.
+ </para>
+ </section>
+
+
+ <section>
+ <title>Adding Alias Dereferencing Functionality To Backends</title>
+ <para>
+ The only other alternative design would be to delegate alias
+ dereferencing to backends. This as mentioned before further
+ complicates backend implementations making life even more
+ difficult for backend implementors. It also limits aliases,
+ preventing their use across DIBs. Alias dereferencing design
+ and implementation would be highly specific to the nature of the
+ backend's backing store and would have to be implemented for
+ each backend. When analyzing the possibilities of this option
+ we would have to focus on a specific backend, which makes the
+ exercise valid for only that backend. Nevertheless the
+ exercise will lead to a better understanding of the hurdles to
+ overcome within backends in general. For the exercise we chose
+ the default Jdbm based backend or modjdbm. See the module
+ documentation for more details on its operation. We will
+ presume the reader is already familiar with its design and its
+ implementation.
+ </para>
+
+ <para>
+ The modjdbm search algorithm factors scope directly into a
+ modified search filter's tree using a special type of node
+ called a ScopeNode. The search engine creates a new tree with a
+ conjuction node at the root. It attaches the ScopeNode
+ underneath the root along with the filter expression tree
+ generated from the user supplied search filter. This is done
+ before the optimization stage where the tree is evalutated by
+ the search optimizer. Introduction of the scope node before
+ optimization considers scope while deciding the optimal search
+ route. If the ScopeNode is chosen as the iteration loop a
+ Cursor is created over entry ids which comply with search scope
+ requirements based on the search base. For subtree scope the
+ ids of all descendants of the search base and the base entry
+ itself are returned. The cursor operates by performing a full
+ index scan on the DN index testing each entry to see if it is
+ accepted by a descendant Assertion. Entry DN's accepted by the
+ assertion have their ids returned. The optimizer rarely selects
+ the ScopeNode for iteration in subtree scope, due to an
+ inefficient full index scan. The search algorthim in most cases
+ opts to use the ScopeNode in assertion checks rather than in
+ iteration loops. Whether the ScopeNode is used in iteration or
+ for assertion checks, the same Assertion is used to validate
+ entries to return. While iterating the candidate is accepted by
+ the assertion and in a lookup the candidate is also accepted or
+ rejected by the assertion.
+ </para>
+
+ <para>
+ At the present moment the assertion used for the ScopeNode of
+ a subtree search leverages a single DN to determine if a
+ candidate is a descendant. In derefInSearching mode, all
+ aliases and any indirect chains can be detected before the
+ search begins. The DNs of these aliases can be used to build
+ a composite disjunction Assertion for the ScopeNode used in
+ iterations and lookups. When used in iteration, the Cursor
+ built for the ScopeNode equiped with the disjunction Assertion,
+ will return candidates under and at all the alias DNs. In
+ lookups, the disjunction Assertion will accept the ids of
+ entries that are aliased as well as their descendants.
+ </para>
+
+ <para>
+ The composite descendant Assertion built on multiple DNs can be
+ spared the trouble of testing each candidate against all aliased
+ DNs. Aliased entry DNs and the base DN can be consolidated
+ depending on the relationships between the search base and the
+ aliased entries. If an aliased entry is a descendant of the
+ search base then it need not be added to the Assertion. The
+ subtree search on the base will eventually included the aliased
+ DN entry and its descendants. Likewise the base DN need not
+ be added if an aliased entry refers to a parent of the DN. The
+ subtree search from the aliased parent will eventually include
+ the base entry and its descendants. This technique can be used
+ to consolidate M related DNs into one DN which is the top most
+ parent of all descendant DNs. DN consolidation makes simple
+ cycles irrelavant to the search without dealing with redundant
+ returns or infinite loops.
+ </para>
+
+ <para>
+ The one detail left out of all is the mechanism for detecting
+ the set of aliases dereferenced in the search and making their
+ aliased entry DNs available to the search engine. A special
+ index can be built to track aliased names unlike the way normal
+ indices work. This special index would map the DN of the alias
+ to the DN of the entry the alias refers to. The search engine
+ would start by scanning the keys of the index looking for DNs
+ that are descendants of the search base. The descendant DNs
+ represent the DNs of all the aliases existing under the search
+ base. The values of these DNs are appended to the set of DNs
+ that we need to add to the ScopeNode Assertion. After the
+ initial scan a similar scan is performed for every value added
+ to the set until all values added have been checked to see if
+ they have descendant aliases. This way we capture all DNs
+ involved in alias chains. In effect, alias dereferencing is
+ being performed here for all aliases before the search begins.
+ Once all possible aliased entry DNs are resolved and accumulated
+ within a set, the consolidation process can begin. The
+ remaining DNs after consolidation are used to build the subtree
+ ScopeNode's Assertion. Search then continues in the same
+ fashion as it has before. Surprisingly the solution is clean
+ and can be encapsulated outside of the search mechanism.
+ </para>
+
+ <para>
+ The modjdbm design for alias dereferencing works out
+ surprisingly well. The process of dereferencing and the
+ application of filter selection criteria are more seperable
+ than we had first imagined. The performance degradation due to
+ alias dereferencing is nominal. The issues described within
+ the "Future Considerations" section to follow do not hold with
+ such a design - server side sorts can still be implemented
+ without elaborate designs. The only drawback is the inability
+ to implement DIB crossing aliases. Situations requiring such
+ constructs can rely on the use of referrals instead. These
+ surprising conclusions lead us to believe that alias handling
+ is best left upto the individual backend.
+ </para>
+ </section>
+
+ <section>
+ <title>Furture Considerations</title>
+ <para>
+ Another consideration for choosing between these approaches is
+ the affect it will have on the ease in which other aspects of
+ search will be designed and implemented. Namely we are
+ concerned with support for search operational modifiers like
+ control extentions. An example of a popular search control
+ extention is the server side sorting control. This control
+ enables clients with a small memory foot print which cannot
+ possibly hold the entire result set for sorting search results
+ by delegating the sort to the server. The entries are returned
+ sorted based on an attribute specified by the control.
+ </para>
+
+ <para>
+ The most efficient implementation for server side sorting would
+ leverage the sorted indicies of backends to have them return
+ entries in sorted order. The alternative of caching the result
+ set on the server after a search to sort the result before
+ returning it would consume too much memory and processing time.
+ Backends could be asked to leverage their specific indexing
+ scheme to return entries already sorted since indices usualy
+ maintain their keys in sorted order. It would be a waste to
+ not take advantage of this, only to spend time and memory to
+ sort the results afterwords.
+ </para>
+
+ <para>
+ The design where alias dereferencing is handled outside of
+ backends through subordinate searches on aliased entries would
+ fragment the sorted resultset returned by search cursors. If a
+ parent search returning sorted entries stops at some alias entry
+ to return the sorted entries of a subordinate search then there
+ will be a discontinuity in sorting order. The subordinate
+ search would not return entries in order after the last entry
+ returned by the parent. Likewise when the subordinate returns
+ its last entry, there is a discontinuity again in the sorting
+ order when the parent search resumes where it left off. Without
+ caching the entire set of entrys then iterating over them once
+ again for the return to the client in sorted order, it would be
+ virtually impossible to manage server side entry sorting
+ controls. Doing so would unnecessarily consume both space and
+ time.
+ </para>
+
+ <para>
+ ????
+ In the case of implementing alias dereferencing within the Jdbm
+ based backend, modjdbm, the problem would still persist.
+ </para>
+ </section>
+ </section>
+ </section>
+
+ <section>
+ <title>Alias Handling Implementation</title>
+
+ <para>
+ We have decided to embed alias handling functionality into backends
+ enabling rapid alias handling without allowing the creation of DIB
+ crossing aliases. The following section elaborates on the details
+ of the implementation with respect to the default backend based on
+ JDBM. The implementation of the JDBM backend is applicable to the
+ the implementation for the BerkeleyDB backend due to their extreme
+ similarity. Other backend modules like the jdbc backend will be
+ very different.
+ </para>
+
+ <section>
+ <title>The Implementation of Alias Dereferencing in Backends</title>
+
+ <para>
+ The implementation shall separate alias handling into categories
+ based on scope and dereferencing modes. These search parameters
+ are request specific. The scope parameter is made available to the
+ backend through the search method as a method argument. The alias
+ dereferencing mode is not and must be made available. The lack of
+ access to the dereferencing mode parameter raises some questions
+ regarding the handling of request parameters. There presently is
+ no localized access mechanism for request scope parameters. In
+ contrast, session scope parameter alteration and access is
+ centralized and well defined within the ClientManager and its
+ helper interfaces. Perhaps there needs to be a similar central
+ facility to access and alter mutable request parameters. The answer
+ to this question is beyond the scope of this document and it needs
+ to be resolved before implementing any request parameter dependent
+ functionality such as alias dereferencing.
+ </para>
+
+ </section>
+ </section>
+
+ <section>
+ <title>Future</title>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+ </section>
+
+ <section>
+ <title>Faults</title>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+ </section>
+
+</article>
Added: incubator/directory/eve/branches/start/src/docbook/design/output-module.xml
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/docbook/design/output-module.xml Thu Jun 24 00:06:35 2004
@@ -0,0 +1,194 @@
+<?xml version="1.0"?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD Simplified DocBook XML V4.1.2.5//EN"
+ "http://www.oasis-open.org/docbook/xml/simple/4.1.2.5/sdocbook.dtd">
+
+<article class="whitepaper">
+ <title>Module Implementation</title>
+
+ <articleinfo>
+ <author><othername>akarasulu</othername></author>
+ <editor><othername>$Author: bearcej $</othername></editor>
+ <revhistory>
+ <revision>
+ <revnumber>$Revision: 1.6 $</revnumber>
+ <date>$Date: 2003/05/03 01:45:23 $</date>
+ <revdescription>
+ <para>
+$Log: output-module.xml,v $
+Revision 1.6 2003/05/03 01:45:23 bearcej
+Refix image URLs
+
+Revision 1.5 2003/05/03 01:43:08 bearcej
+Add maven file to help generate server site.
+Modify graphic links again.
+Remove tabs from doc files and fix linefeeds.
+
+Revision 1.4 2003/05/03 01:21:32 bearcej
+Remove tabs from doc files and fix linefeeds.
+
+Revision 1.3 2003/04/08 02:29:55 bearcej
+* Clean up project.properties
+* Fix logos in project.xml
+* Fix links to image files in docs
+
+Revision 1.2 2003/03/23 13:24:46 akarasulu
+Added these files from the ALPHA-0_7 branch.
+
+Revision 1.1.2.3 2003/03/15 17:18:35 bearcej
+Fixed figure tags to conform to simple docbook.
+Modified Files:
+ Tag: ALPHA-0_7
+ output-module.xml
+
+Revision 1.1.2.2 2003/03/10 23:43:32 akarasulu
+Moved links so that image references point to /image/design. Note that
+references do not have a [.] in front since the maven driven transforms
+automatically append [.] to references.
+
+Revision 1.1.2.1 2003/03/10 23:24:21 akarasulu
+Moved design documentation from docs/design to src/docbook/design.
+
+Revision 1.1.2.2 2003/03/09 01:33:58 akarasulu
+Completed OuputModule documentation and refactored annon inner class for
+handler into named inner class.
+
+Revision 1.1.2.1 2003/03/03 04:49:25 akarasulu
+Added as placeholders for now.
+
+ </para>
+ </revdescription>
+ </revision>
+ </revhistory>
+ </articleinfo>
+
+ <abstract>
+ <para>
+ The OutputModule implements the OutputManager service interface used
+ to transmit LDAPv3 ASN.1 BER encoded message responses to clients on
+ a server OutputStream. The module is implemented as a stage which
+ asynchronously processes OutputEvents carrying the message to
+ transmit as well as the client key used to identify the client
+ stream.
+ </para>
+ </abstract>
+
+ <section>
+ <title>Document TODOs:</title>
+ <itemizedlist>
+ <listitem><para>
+ Add diagrams.
+ </para></listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Implementation</title>
+
+ <para>
+ The OutputManager interface extends two subinterfaces:
+ OutputListener and ClientManagerSlave. The OutputListener interface
+ gives the OutputManager its event processing character by defining
+ a single method called writeResponse to process its OutputEvent
+ argument. The OutputModule which implements OuputManager, is
+ implemented as a OutputEvent processing stage. The OutputEvents are
+ delivered through the OutputListener.writeResponse() method which
+ returns immediately after enqueueing the event onto the stage event
+ queue.
+ </para>
+
+ <para>
+ The ClientManagerSlave interface is extended by the OutputManager to
+ prevent containers of this module from detecting a cyclic dependency
+ between the ClientManager and eventually this module. This
+ interface essentially defines a method that is called by the
+ ClientManager on initialization to set the handle of these slave on
+ the ClientManager service. This avoids the use of the conventional
+ service life-cycle method to initialize the handle on the
+ ClientManager. If the handle were gotten by the ServiceManager fed
+ into the service method, the cyclic dependency would be caught and
+ the server would not start. Hence this module is a slave to the
+ ClientManager since it must have a member handle initialized by it.
+ </para>
+
+ <para>
+ The OutputManager interface defines three other service methods.
+ These are: write(), register() and unregister(). The write() method
+ is a special synchronous flush of a response message which bypasses
+ the asynchronous stage processing of the OutputEvent. It directly
+ requires the client key and the message PDU in the form of an
+ InputStream with both provided as arguments. The synchronous write
+ method is a work around to bypass staged processing to facilitate
+ the synchronous delivery of search responses. The search request
+ process calls this method to maintain the order of responses in a
+ train of search entry response message envelopes. The other two
+ methods are defined to enable the registration and unregistration
+ of client's that must have response messages delivered to them.
+ When client's connect to the server, the ListenerModule adds the
+ client to the ClientManager. The ClientManager then on behalf of
+ the listener registers the client's InputStream with the
+ InputManager and registers the client's OutputStream with the
+ OutputManager. This enables the stage pipling to go full circle by
+ recieving input requests, processing then, and returning the
+ responses to the client.
+ </para>
+
+ <figure>
+ <title>OutputModule's OutputEventHandler Sequence Diagram</title>
+ <graphic fileref="../images/OutputEventHandlerHandleEvent.gif"/>
+ </figure>
+
+ <para>
+ This stage is extremely simple. Like other stages its driver
+ dequeues an incoming event, and creates an annonymous inner Runnable
+ to drive the call to the stage event handler's handleEvent method in
+ the execution context of a stage worker thread. The OutputEvent is
+ provided as the sole argument to the handleEvent() method on the
+ EventHandler. The gist of the work done within the write() method
+ of the module which is called by the handler. Essentially the
+ handler just extracts the client key and the InputStream to the
+ response buffer from the OutputEvent argument. It then feeds them
+ both into the synchronous write() method as arguments. The same
+ write() method used by the search request processor to synchronously
+ deliver response messages is used to asynchronously deliver messages
+ when driven by a worker thread. The trivial eventHandler method is
+ depicted in the sequence diagram above.
+ </para>
+
+ <figure>
+ <title>OutputModule's write() Method Sequence Diagram</title>
+ <graphic fileref="../images/OutputModuleWrite.gif"/>
+ </figure>
+
+ <para>
+ As can be seen from the sequence diagram above depicting the flow of
+ the write() method, the client key is used to lookup the OuputStream
+ of the client. Then after acquiring a lock on the output lock
+ object, a while loop is entered which reads from the InputStream
+ argument. The InputStream reads from the encoded response message
+ buffer constructed by the upstream encoder stage. Once the buffer
+ has been consumed or the client key expires the loop terminates.
+ For all practical purposes it can now be concluded that the reponse
+ message has been delivered to the client. notifyAll() is then
+ called to awaken threads blocked waiting for the OutputStream of the
+ client.
+ </para>
+
+ </section>
+
+ <section>
+ <title>Future</title>
+
+ <para>
+ This module is pretty solid.
+ </para>
+ </section>
+
+ <section>
+ <title>Faults</title>
+
+ <para>
+ None so far.
+ </para>
+ </section>
+
+</article>
Added: incubator/directory/eve/branches/start/src/docbook/design/protocol-module.xml
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/docbook/design/protocol-module.xml Thu Jun 24 00:06:35 2004
@@ -0,0 +1,979 @@
+<?xml version="1.0"?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD Simplified DocBook XML V4.1.2.5//EN"
+ "http://www.oasis-open.org/docbook/xml/simple/4.1.2.5/sdocbook.dtd">
+
+<article class="whitepaper">
+ <title>Module Implementation</title>
+
+ <articleinfo>
+ <author><othername>akarasulu</othername></author>
+ <editor><othername>$Author: akarasulu $</othername></editor>
+ <revhistory>
+ <revision>
+ <revnumber>$Revision: 1.7 $</revnumber>
+ <date>$Date: 2003/08/22 21:15:54 $</date>
+ <revdescription>
+ <para>
+$Log: protocol-module.xml,v $
+Revision 1.7 2003/08/22 21:15:54 akarasulu
+Merged changes made in the USING_PROVIDER_FRAMEWORK branch of the
+server. I don't suspect she will be working well at this point. Lots
+of overhauling required now.
+
+Revision 1.3.2.2 2003/05/17 16:58:52 akarasulu
+started an addendum section for refactorings which will be used to refactor
+this document to synch it up with the code changes currently under way w/i
+the USING_PROVIDER_FRAMEWORK brach.
+
+Revision 1.3.2.1 2003/05/05 17:28:54 akarasulu
+Moving towards the request handler flywieght pattern away from the
+per request dedicated processor based design of the protocol engine.
+
+Revision 1.3 2003/04/08 02:29:55 bearcej
+* Clean up project.properties
+* Fix logos in project.xml
+* Fix links to image files in docs
+
+Revision 1.2 2003/03/23 13:24:46 akarasulu
+Added these files from the ALPHA-0_7 branch.
+
+Revision 1.1.2.4 2003/03/15 22:30:30 bearcej
+Fix last figure href.
+
+Revision 1.1.2.3 2003/03/15 17:16:47 bearcej
+Fixed figure tags to conform to simple docbook.
+Modified Files:
+ Tag: ALPHA-0_7
+ protocol-module.xml
+
+Revision 1.1.2.2 2003/03/10 23:43:32 akarasulu
+Moved links so that image references point to /image/design. Note that
+references do not have a [.] in front since the maven driven transforms
+automatically append [.] to references.
+
+Revision 1.1.2.1 2003/03/10 23:24:21 akarasulu
+Moved design documentation from docs/design to src/docbook/design.
+
+Revision 1.1.2.6 2003/03/09 00:36:54 akarasulu
+Finished encoder docs and refactored inner annonymous handler to be a
+named inner class.
+
+Revision 1.1.2.5 2003/03/08 23:38:42 akarasulu
+Completed protocol engine documentation along with subsections for the
+various protocol request processors used.
+
+Revision 1.1.2.4 2003/03/07 20:50:47 akarasulu
+*** empty log message ***
+
+Revision 1.1.2.3 2003/03/07 20:49:33 akarasulu
+Adding Bind docs
+
+Revision 1.1.2.2 2003/03/06 23:11:26 akarasulu
+Proof read decoder module and added some content to protocol module docs.
+
+Revision 1.1.2.1 2003/03/03 04:49:25 akarasulu
+Added as placeholders for now.
+
+ </para>
+ </revdescription>
+ </revision>
+ </revhistory>
+ </articleinfo>
+
+ <abstract>
+ <para>
+ The ProtocolModule is the heart of the server. It contains the
+ logic required to service each LDAPv3 protocol request and if need
+ be construct one or more response PDUs. The module implements the
+ RequestListener interface to have RequestEvents delivered for
+ processing. It is implemented as a stage and consequently can
+ process several requests in parallel.
+ </para>
+ </abstract>
+
+ <section>
+ <title>Document TODOs:</title>
+ <itemizedlist>
+ <listitem><para>
+ Add sequence diagrams.
+ </para></listitem>
+ <listitem><para>
+ Add link to relavent rfc 2251 sections.
+ </para></listitem>
+ <listitem><para>
+ Add diagrams showing the composition of both request and
+ where relavent response envelopes.
+ </para></listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Background</title>
+
+ <para>
+ The decoding stage of the server delivers decoded Requests to the
+ protocol stage using RequestEvents. The request events carry the
+ Request and the ClientKey for the client submitting the Request. It
+ is the responsibility of the protocol stage to service each request
+ using the resources available.
+ </para>
+
+ <para>
+ Based on the message type, the manner in which Requests are serviced
+ differs. The majority of Request messages produce a single Response
+ as a reply. AbandonRequest, and UnbindRequests produce no Response
+ at all. Conversely, in the course of servicing a SearchRequest many
+ Responses of various message types may be generated in reply.
+ According to RFC 2251 a SearchRequest must reply with a
+ SearchResponseDone to mark the end of the reply. Before
+ transmission of the SearchResponseDone, zero or more (in any order)
+ SearchResponseEntry, SearchResponseReference and ExtendedResponses
+ may be returned to the client. These vastly differing modes of
+ Request handling makes it difficult to devise a generalize mechanism
+ to process all requests. The best approach would be to devise a
+ processing scheme for each category of request.
+ </para>
+
+ <para>
+ The protocol imposes no requirement enforcing ordered response
+ delivery between request messages. The message sequence identifier
+ is used to prevent the protocol from having to impose such
+ requirements. Hence the response to request 3 may be returned
+ before the response to request 1. The server's seda architecture
+ takes advantage of this be enabling the asynchonous staged delivery
+ of responses back to a client. Whenever a response to a request is
+ composes it is returned back to the client asynchronously without
+ concern for the order of delivery. The multiresponse nature of the
+ search request does however impose a response delivery order within
+ a message request. All Responses delivered in reply to a
+ SearchRequest have the same message sequence identifier. This way
+ they are all associated with the same SearchRequest. Our only
+ problem is the need to return some search responses before others
+ in a asynchronous response delivery environment.
+ </para>
+
+ <para>
+ The SearchRequest presents many design hurdles to overcome. The
+ server must synchronize the delivery of search responses within a
+ SearchRequest. Searches using the sort control extention cannot
+ return sorted entries without synchronous delivery to maintain
+ sorting order. Furthurmore we must ensure the last response sent to
+ be the SearchResponseDone message.
+ </para>
+ </section>
+
+
+ <section>
+ <title>Architecture</title>
+
+ <para>
+ As a stage the work of processing RequestEvents is delegated to the
+ stage worker threads. The worker threads as in other stages drive
+ the synchronous call to the stage's event handler. The stage event
+ handler accepts event's and specifically with regard to this module
+ it requires events to be RequestEvents. So far these aspects to the
+ module's architecture are really based on the architecture of a
+ stage.
+ </para>
+
+ <para>
+ The use of the new Message Framework encapsulates protocol request
+ parameters and other message parameters within a Request object.
+ The Request object can be used to store request processing state
+ rather than embedding state tracking into some kind of request
+ processor object for each request. The FlyWeight design pattern
+ can be used to have a specific processor instance service all
+ requests of a particular request message type. Previously before
+ the Message Framework, a specific processor would be instantiated to
+ track and process each request. Once processing was complete the
+ processor memory would be reclaimed. Each incomming request would
+ instantiate a processor. The processor itself served to encapsulate
+ request protocol parameters like a request bean to prevent other
+ parts of the system from having to deal with ASN.1 compiler stubs.
+ Now with a clean explicit API to represent messages independent of
+ the ASN.1 stub compiler and BER library used we can expose a Request
+ bean rather than a processor wrapping a stub class.
+ </para>
+
+ <para>
+ Still the specific processing of each type of protocol requests is
+ best handled using separate request processor implementations. For
+ now we will just call them handlers. They really are specific
+ request message type handlers with the new Message framework. A
+ handler unlike a processor, can be used to safely handle several
+ requests concurrently whereas a processor is dedicated to an
+ individual request. We can easily find the request handler for a
+ request based on the message type enumeration. A RequestHandler
+ interface is designed to standardize handler operations. The
+ stage's handler selects the specific request handler for the
+ respective request off of a switch on the protocol message type.
+ After assigning the Request to a handler, generic handling interface
+ methods can be used to manage the process without regard to type
+ specifics.
+ </para>
+
+ <para>
+ The work of a request handler is performed in a simple handleRequest
+ method that returns a potentially null handle on a Response. The
+ stage's event handler simply calls this method on the processor. If
+ the request requires a response the response is handed off to the
+ next downstream stage (the decoder) in the form of a ResponseEvent.
+ The response if one is to be returned is the LDAPMessage object
+ returned by the process method.
+ </para>
+
+ <para>
+ The use of processors to handle requests based on type is a form of
+ the Reactor design patten and has several benefits. First and
+ foremost it separates the handling of each request out into separate
+ classes thereby minimizing complexity. Second it provides a place
+ where request specific parameters can be managed, like the request
+ PDU envelope (an LDAPMessage instance). Finally a common super
+ interface standardizes request event handling by manipulating each
+ request processor implementation through the methods of this common
+ interface.
+ </para>
+ </section>
+
+ <section>
+ <title>Implementation</title>
+
+ <para>
+ The best approach to describing the implementation is to generally
+ describe the event handling from an enqueue onto this stage's queue
+ on upto the death of a stage worker thread without dealing with the
+ specifics of each processor. The specifics of each processor's
+ implentation is handled in separate request specific sections.
+ </para>
+
+ <para>
+ As noted, this module is implemented as a stage to enable parallel
+ processing of multiple request events. Event processing is handled
+ asynchronously by stage worker threads. The RequestListener's
+ requestReceived method implementation simply enqueues the
+ RequestEvent argument onto the stage event queue. Hence, the
+ requestReceived method called by an upstream decoder stage worker
+ thread returns immediately.
+ </para>
+
+ <para>
+ Once the RequestEvent is enqueued, the stage dedicates a worker to
+ drive an instance of an annonymous Runnable class. The Runnable's
+ run method, as in all stages, calls the stage's EventHandler passing
+ it the RequestEvent. A named inner class called a
+ RequestEventHandler is defined and an instance of it is instantiated
+ within the module's default constructor. This is the EventHandler
+ implementation used for this stage. The RequestEventHandler's
+ handleEvent method is called by the annonymous Runnable's run
+ method.
+ </para>
+
+ <figure>
+ <title>ProtocolModule's RequestEventHandler Sequence Diagram</title>
+ <mediaobject><imageobject>
+ <imagedata fileref="images/RequestEventHandlerHandleEvent.gif"/>
+ </imageobject></mediaobject>
+ </figure>
+
+ <para>
+ The primary function of the eventHandler implementation is to
+ instantiate the correct RequestProcessor matching the request and
+ call the RequestProcessor.process() method. Initially the handler
+ checks that the event is an instance of RequestEvent, and accesses
+ the parameter's of the request packaged into the RequestEvent.
+ These include the request envelope as an LDAPMessage, the ClientKey,
+ and the message type value used in the switch to follow. The switch
+ is on the message type and it is used to instantiate the appropriate
+ RequestProcessor. Once the RequestProcessor is set the current
+ thread of execution is bound to the processor within a ThreadLocal
+ to access request parameters during the coarse of processing the
+ request without passing around several variables. The service and
+ initialize life-cycle methods of the RequestProcessor are called to
+ prepare it for the process invokation. The call to the process
+ method returns a handle on a response if one exists. If a response
+ is to be returned by the processor it is packaged into a
+ ResponseEvent and delivered to the next downstream stage, the
+ encoder. Whether or not a response is generated the executing
+ thread is disassociated with the RequestProcessor after the call
+ to process. After this last step the handler returns. The entire
+ sequence is depicted in the sequence diagram above. The specifics
+ of each RequestProcessor's process method is discussed in details
+ within the sections to follow.
+ </para>
+
+ <section>
+ <title>AbandonRequestProcessor</title>
+
+ <para>
+ The purpose of the AbandonRequestProcessor is to implement the
+ abandon protocol operation. This processor is not yet
+ implemented. According to the protocol this operation does not
+ produce as response.
+ </para>
+ </section>
+
+ <section>
+ <title>AddRequestProcessor</title>
+
+ <para>
+ The purpose of the AddRequestProcessor is to implement the add
+ protocol operation. This operation adds a single new entry at
+ the base of an existing entry. According to the protocol this
+ operation must produce a response indicating success or failure.
+ </para>
+
+ <para>
+ The processor is created by passing the client's key and the
+ request envelope to the constructor. On initialization the
+ response envelope is allocated and populated minimally with the
+ message sequence id and an empty AddResponse object. The
+ service method initializes handles on dependent modules: the
+ UnifiedBackend and the EventManager.
+ </para>
+
+ <figure>
+ <title>
+ AddRequestProcessor's process() Sequence Diagram
+ </title>
+ <mediaobject><imageobject>
+ <imagedata fileref="images/AddRequestProcessorProcess.gif"/>
+ </imageobject></mediaobject>
+ </figure>
+
+ <para>
+ Before wasting time and resources by investigating the contents
+ of the request envelope the processors process() method checks
+ to see if the entry to be added already exists by calling the
+ hasEntry method of the UnifiedBackend. The protocol request
+ contains the set of attribute identifiers and their single or
+ multiple values. These values are extracted from the request
+ envelope using the stubs generated by the Snacc4J compiler.
+ These attributes and values are added to an empty LdapEntry
+ returned by the UnifiedBackend. The LdapEntry implementation is
+ constructed by the AtomicBackend associated with the naming
+ context under which the name of the entry to be added exists.
+ The UnifiedBackend automatically routes these kinds of calls to
+ the naming context's AtomicBackend. Once populated a pre-event
+ announcement via the fireBefore() method of the EventManager is
+ made. The create method on the UnifiedBackend is called to
+ create (add) this new attribute. Immediately there after
+ another post-addition protocol event is fired via the
+ EventManager's fireAfter method. See the sequence diagram for
+ high level view of the add operation's success pathway.
+ </para>
+ </section>
+
+ <section>
+ <title>BindRequestProcessor</title>
+
+ <para>
+ The purpose of the BindRequestProcessor is to implement the
+ bind protocol operation. The processor depends on the
+ EventManager, UnifiedBackend and AuthenticationManager services.
+ The bind operation generates a bind response no matter what the
+ results of the bind operation.
+ </para>
+
+ <para>
+ An instance of the bind processor is created by passing the
+ ClientKey, a handle to the ClientManager service and the
+ LDAPMessage request as arguments to the constructor. The call
+ to initialize allocates a response LDAPMessage to the bind
+ request which is an empty envelope. Some preparations are made
+ to the request envelope like adding the message sequence id, and
+ initializing the BindResponse object. The service method is
+ next in line and is called by the handler after calling
+ initialize. The service method is used to pass service handles
+ to the processor. The handle to the AuthorizationManager, the
+ UnifiedBackend and the EventManager are acquired here.
+ </para>
+
+ <figure>
+ <title>
+ BindRequest Processor's process() Sequence Diagram
+ </title>
+ <mediaobject><imageobject>
+ <imagedata fileref="images/BindRequestProcessorProcess.gif"/>
+ </imageobject></mediaobject>
+ </figure>
+
+ <para>
+ After all life-cycle methods are invoked the process method is
+ called. The highlevel sequence of events within the process()
+ method are shown in the sequence diagram above. Currently the
+ only available authentication method is simple. SASL based
+ authentication is not available. Therefore the diagram
+ represents the steps towards successfully authenticating a user
+ via the simple method pathway. It does not show error handling
+ functionality within the processor. SASL authentication
+ attempts and various exceptions which may occur result in the
+ construction of an alternative LDAPMessage response object. In
+ these cases the error or unavailability of an operation result
+ in a response returning the respective LDAP error code along
+ with a descriptive message regarding the error.
+ </para>
+
+ <para>
+ The normal operational pathway for the processor first results
+ in the construction of a bind protocol event which is delivered
+ to protocol event listeners via the EventManager service. This
+ pre-event announcement is depicted in call 1.1 of the diagram.
+ The processor then invokes the loginSimple method of the
+ AuthenticationManager which either results in a LoginException
+ or returned a valid Pricipal object. Presuming the correct
+ credentials were supplied, the processor then creates the
+ client's session by calling create on the ClientManager service
+ interface. Thereafter the processor fires a post-event
+ announcement using the fireAfter method on the EventManager and
+ returns.
+ </para>
+
+ <para>
+ Exceptional conditions at any point result in the return of an
+ envelope packaged with the LDAP error code and a descriptive
+ message.
+ </para>
+ </section>
+
+ <section>
+ <title>CompareRequestProcessor</title>
+
+ <para>
+ The purpose of the CompareRequestProcessor is to implement the
+ compare protocol operation. The processor depends on the
+ EventManager, and the UnifiedBackend services. The purpose of
+ the operation is to evaluate an attribute assertion on an entry
+ specified by DN. The compare operation generates a compare
+ response no matter whether the operation succeeds, fails or
+ generates an exception during processing.
+ </para>
+
+ <figure>
+ <title>
+ CompareRequestProcessor's process() Sequence Diagram
+ </title>
+ <mediaobject><imageobject>
+ <imagedata fileref="images/CompareRequestProcessorProcess.gif"/>
+ </imageobject></mediaobject>
+ </figure>
+
+ <para>
+ The processor is instantiated by passing the client key and the
+ request message envelope as arguments to the constructor. On
+ initialization the response message envelope is allocated and
+ populated with the message sequence id and an empty
+ CompareResponse. The handles on the dependent UnifiedBackend
+ and EventManager services are acquired after initialization with
+ a call to the processor's service method.
+ </para>
+
+ <para>
+ Once the process method is called the processor attempts to
+ resusitate the LdapEntry to be tested using the attribute value
+ assertion contained in the compare request envelope. Next the
+ entries attributes are tested to see if they comply with the
+ assertion. The results of the test are then packaged into the
+ compare response returned within the LDAPMessage envelope.
+ Before returning the response the process method announces
+ operation completion via the EventManager's fireAfter method.
+ </para>
+
+ <para>
+ Exceptional conditions at any point result in the return of an
+ envelope packaged with the LDAP error code and a descriptive
+ message.
+ </para>
+ </section>
+
+ <section>
+ <title>DelRequestProcessor</title>
+
+ <para>
+ The purpose of the DelRequestProcessor is to implement the
+ delete protocol operation. The processor depends on the
+ EventManager, and the UnifiedBackend services. The purpose of
+ the operation is to remove a single entry specified by DN. The
+ operation according to the LDAPv3 protocol will fail if the
+ target entry has children. The delete operation generates a
+ response no matter whether the operation succeeds, fails or
+ generates an exception during processing.
+ </para>
+
+ <figure>
+ <title>
+ DelRequestProcessor's process() Sequence Diagram
+ </title>
+ <mediaobject><imageobject>
+ <imagedata fileref="images/DelRequestProcessorProcess.gif"/>
+ </imageobject></mediaobject>
+ </figure>
+
+ <para>
+ The processor is instantiated by the protocol engines stage
+ event handle by a call to the constructor passing in the client
+ key and the request message envelope. On initialization the
+ response message envelope is allocated and populated with the
+ message sequence id and an empty delete response object.
+ Handles to the dependent UnifiedBackend and EventManager
+ services are initialized on the call to the service life-cycle
+ method before the process method is called.
+ </para>
+
+ <para>
+ The process method first resusitates the target entry to delete
+ from the UnifiedBackend with a read call that returns a handle
+ on an LdapEntry. This confirms the existance of the entry and
+ facilitates the call to delete() which requires an LdapEntry as
+ the argument. Then a pre-event announcement is made via a call
+ to the fireBefore method of the EventManager. The call to the
+ delete method is made using the returned LdapEntry. Finally
+ before returning the response envelope confirming the deletion,
+ a post protocol operation is announced via the fireAfter method
+ of the EventManager.
+ </para>
+
+ <para>
+ Exceptional conditions at any point result in the return of an
+ envelope packaged with the LDAP error code and a descriptive
+ message.
+ </para>
+ </section>
+
+ <section>
+ <title>ExtendedRequestProcessor</title>
+
+ <para>
+ The purpose of the ExtendedRequestProcessor is to implement the
+ extended protocol operation. The processor depends on the
+ EventManager, and the UnifiedBackend services. The purpose of
+ the operation is to enable protocol compliant operation
+ extentions. The request contains an OID and a binary payload
+ holding the parameters required in an operation specific format.
+ The operation is simply a pass through to execute some type of
+ application specific or server specific operation. The extended
+ operation generates a response no matter whether the operation
+ succeeds, fails or generates an exception during processing.
+ </para>
+
+ <figure>
+ <title>
+ ExtendedRequestProcessor's process() Sequence Diagram
+ </title>
+ <mediaobject><imageobject>
+ <imagedata fileref="images/ExtendedRequestProcessorProcess.gif"/>
+ </imageobject></mediaobject>
+ </figure>
+
+ <para>
+ The processor is instantiated by passing the client key, the
+ request message envelope and a handler map to the constructor.
+ The handler map contains a map of OID Strings to ExtReqHandler
+ instances. These handlers are simple implementations of
+ functions with assigned OIDs. They take the payload as a byte
+ array argument which is extracted from the extended request
+ envelope and return a byte array. The returned byte array
+ represents the extended response payload which is packaged into
+ the response envelope returned by the processor's process
+ method. These extended request handlers and the OID to handler
+ map are created by the protocol engine during the module's
+ configuration life-cycle phase.
+ </para>
+
+ <para>
+ By providing the extended request handler map in the constructor
+ the processor can invoke the appropriate handler on the request
+ payload and hence respond to the request using the resultant
+ response payload. Following instantiation the processor is
+ initialized creating the empty extended request message envelope
+ populated with the message sequence id and an empty
+ ExtendedResponse object. Then before the process method is
+ called the service method is called to acquire handles on the
+ dependent EventManager service. It is very likely that other
+ service dependencies will exist however since we have not
+ implemented any of these extended request handlers we know of
+ none for now. Eventually it will be necessary to enable
+ extended request handlers with handles to other dependent
+ modules. This will require a change to the extended request
+ handler or to its implementation to have it implement the
+ Serviceable interface. Handles to dependent services within
+ the server to do the work of processing the extended request
+ can be obtained through this standard Avalon life-cycle method.
+ </para>
+
+ <para>
+ The process method immediately announces the arrival of an
+ extended request by calling the fireBefore method of the
+ EventManager service. It then calls the handle method of the
+ OID specific handler using the extracted payload of the request
+ envelope. Then before the resultant payload is packaged into
+ the response envelope and returned the fireAfter method of the
+ EventManager is called.
+ </para>
+
+ <para>
+ Exceptional conditions at any point result in the return of an
+ envelope packaged with the LDAP error code and a descriptive
+ message.
+ </para>
+ </section>
+
+ <section>
+ <title>ModifyDNRequestProcessor</title>
+
+ <para>
+ The purpose of the ModifyDNRequestProcessor is to implement the
+ modify DN protocol operation. The processor depends on the
+ EventManager, and the UnifiedBackend services. The purpose of
+ the operation is to change the name of an entry and consequently
+ the DN of every descendant entry. The modify DN operation can
+ optionally change the Rdn attribute used by the target entry.
+ The operation generates a response no matter whether it
+ succeeds, fails or generates an exception during processing.
+ </para>
+
+ <figure>
+ <title>
+ ModifyDNRequestProcessor's process() Sequence Diagram
+ </title>
+ <mediaobject><imageobject>
+ <imagedata fileref="images/ModifyDNRequestProcessorProcess.gif"/>
+ </imageobject></mediaobject>
+ </figure>
+
+ <para>
+ The call to the constructor with a client key and the request
+ message envelope is made by the protocol engine stage's event
+ handler. Once instantiated the call initialize again by the
+ event handler allocates a response message envelope populated
+ with the message sequence id and an empty ModifyDNResponse
+ object. The call to the service method next by the handler
+ initializes processor member variables referring to the
+ dependent services.
+ </para>
+
+ <para>
+ The process method of the processor first checks to see if the
+ target entry whose DN is to be modified exists. If the entry
+ exists a pre modify DN announcement is made via the fireBefore
+ method of the EventManager service. Next the modifyRdn method
+ is called on the UnifiedBackend service and then a call is made
+ to fireAfter to announce the completion of the operation on the
+ EventManager service. The results of the operation are returned
+ after being packaged into the response envelope.
+ </para>
+
+ <para>
+ Exceptional conditions at any point result in the return of an
+ envelope packaged with the LDAP error code and a descriptive
+ message.
+ </para>
+ </section>
+
+ <section>
+ <title>ModifyRequestProcessor</title>
+
+ <para>
+ The purpose of the ModifyRequestProcessor is to implement the
+ modify protocol operation. The processor depends on the
+ EventManager, and the UnifiedBackend services. The purpose of
+ the operation is to change, remove or add a set of attribute
+ value pairs to an entry specified by DN. The operation
+ generates a response no matter whether it succeeds, fails or
+ generates an exception during processing.
+ </para>
+
+ <figure>
+ <title>
+ ModifyRequestProcessor's process() Sequence Diagram
+ </title>
+ <mediaobject><imageobject>
+ <imagedata fileref="images/ModifyRequestProcessorProcess.gif"/>
+ </imageobject></mediaobject>
+ </figure>
+
+ <para>
+ The processor is instantiate via a standard constructor call
+ taking the client key and the request message envelope as its
+ arguments. The initialize method call made by the protocol
+ engine stage event handler allocates a response message envelope
+ populated with the message sequence id and an empty
+ ModifyResponse. Finally before assigning a worker to process
+ the request the service method is called by the handler to
+ initialize handles on the dependent services required by this
+ processor.
+ </para>
+
+ <para>
+ Once the worker thread calls process, the target entry is
+ resusitated from the owning context via a call to the
+ UnifiedBackend's read method. Next the resusitated entries
+ are modified according to the changes described by the modify
+ request envelope. At this point before calling update the
+ pre modify operation must be fired, yet it seems to have been
+ overlooked. It needs to be fired. Next a the call to update
+ on the UnifiedBackend is made to effect the changes made to the
+ target entry. Finally before returning the response message
+ envelope the processor needs to call the fireAfter method on the
+ EventManager service yet again this seems to have been
+ overlooked.
+ </para>
+ </section>
+
+ <section>
+ <title>SearchRequestProcessor</title>
+
+ <para>
+ The purpose of the SearchRequestProcessor is to implement the
+ search protocol operation and it is by far the most complex of
+ all the protocol operations. The processor depends on the
+ EventManager, the UnifiedBackend, the Encoder and OutputManager
+ services. The purpose of the operation is to search the
+ directory returning zero or more entries or references to
+ entries while appling search controls to moderate the operation.
+ The operation generates a response no matter whether it
+ succeeds, fails or generates an exception during processing.
+ </para>
+
+ <para>
+ The search operation as mentioned before is the most complex. As
+ a consequence the processor implementation for it is complex as
+ well. The search operation can return one or more responses to
+ the client or zero or more entry or referrals. The search
+ operation uses different responses for each entry returned, from
+ each referral to a remote entry. Referral response message
+ envelopes hence have the url of the entry whereas entry response
+ message envelopes contain the attributes of the entry. Not to
+ mention these response types, at the end of the operation once
+ the search has completed a search done response message must be
+ delivered to the client. The search done response message
+ envelope has yet another makeup.
+ </para>
+
+ <para>
+ While managing the delivery, the search processor must take
+ search controls into account to moderate the operation. For
+ the time being controls are not fully implemented. As a
+ consequence of the need to sychronize the ordered receipt of
+ messages the search processor must use synchronous message
+ delivery methods on the Encoder and the OutputModule for all
+ response messages except the final search done response. These
+ factors complicate the operation of the processor.
+ </para>
+
+ <figure>
+ <title>
+ SearchRequestProcessor's process() Sequence Diagram
+ </title>
+ <mediaobject><imageobject>
+ <imagedata fileref="images/SearchRequestProcessorProcess.gif"/>
+ </imageobject></mediaobject>
+ </figure>
+
+ <para>
+ The processor is instantiated via a call to its constructor
+ using the client key and the request message envelope as
+ parameters. The initialize life-cycle method does nothing since
+ the response message processing can be handled usind more than
+ one type of response unlike other protocol operations.
+ </para>
+
+ <para>
+ Since the processor directly manages and drives the synchronous
+ delivery of all responses except for the final search done
+ response it must communicate with the Encoder and the
+ OutputModule directly without relying on staged event processing
+ pathways within the server. This is why the processor must
+ initialize a handle on both the Encoder and OutputManager
+ services as well as the EventManager and UnifiedBackend services
+ during the service life-cycle method.
+ </para>
+
+ <para>
+ Once processing begins the processor extracts the base DN,
+ search controls and filter information for the search from the
+ request message envelope. A pre search event is then fired from
+ the EventManager service's fireBefore method. Now the processor
+ is ready to call the search method on the UnifiedBackend
+ service. The search simply returns a Cursor which requires a
+ loop to extract the candidate entries to return. Within the
+ loop synchronous calls are made to special method interfaces
+ for synchronous processing on the Encoder and OutputManager
+ services. Once all the entry and referal response messages have
+ been delivered synchronously to the client, the last search done
+ response message envelope is constructed and returned to the
+ caller. This last response message envelope is delivered
+ asynchronously to the client using the standard staged pathways
+ of the server.
+ </para>
+ </section>
+
+ <section>
+ <title>UnBindRequestProcessor</title>
+
+ <para>
+ The purpose of the UnBindRequestProcessor is to implement the
+ unbind protocol operation. The processor depends on the
+ CllientManager only and the handle is passed in the constructor.
+ The purpose of the operation is to drop a client and destroy
+ their session and associated resources. The operation does not
+ generate a response - the client socket drop can be considered
+ the response however clients usually close their connections
+ just after sending this request.
+ </para>
+
+ <figure>
+ <title>
+ UnBindRequestProcessor's process() Sequence Diagram
+ </title>
+ <mediaobject><imageobject>
+ <imagedata fileref="images/UnBindRequestProcessorProcess.gif"/>
+ </imageobject></mediaobject>
+ </figure>
+
+ <para>
+ This very simple processor is instantiated via a call to its
+ constructor requiring as arguments a handle to the ClientManager
+ service, a client key, and the request message envelope. Both
+ the initialize and service life-cycle methods do nothing at all
+ with empty method bodies.
+ </para>
+
+ <para>
+ The process method should announce the unbind protocol operation
+ before and after droping the client connection yet this is not
+ the case. It merely drops the connection through a call to the
+ drop method of the client manager. It returns null indicating
+ that no response is to be returned to the client.
+ </para>
+ </section>
+
+ </section>
+
+
+
+
+ <section>
+ <title>Future</title>
+
+ <para>
+ We need to revaluate whether or not we are using ThreadLocals
+ correctly.
+ </para>
+
+ <para>
+ We need to cleanup the processor code perhaps wrapping access to
+ the Snacc4J generated classes. Later when and if we use other ASN.1
+ stubs only the stub wrappers will have to change.
+ </para>
+
+ <para>
+ We may want to look at using the JNDI provider to access backends
+ rather than going directly through the nexus module. The JNDI
+ provider may be able to transparently manage and encapsulate the
+ referal management code on behalf of the protocol engine.
+ </para>
+
+ <para>
+ We need to implement the AbandonRequestProcessor for the Abandon
+ request type. This will require access to the client's session
+ which may have to hold the executing processor's which will need to
+ be stopped. In this case the RequestProcessor implementations will
+ need to have some form of termination variable that can be checked
+ every now and then by the executing thread. These are problems best
+ solved through aspect oriented techniques.
+ </para>
+
+ <para>
+ Based on the decisions made on using the JNDI provider inside the
+ processors to access backends we may need to put protocol event
+ firing hooks into all processors to fire their respective protocol
+ event.
+ </para>
+
+ <para>
+ Need to make all processors consistant in the way they handle
+ reporting errors. Namely I would like to see stack traces returned
+ to the client only if debugging is enabled.
+ </para>
+
+ </section>
+
+ <section>
+ <title>Faults</title>
+
+ <para>
+ Pre and Post modify protocol events are not fired by the
+ ModifyRequestProcessor.
+ </para>
+
+ <para>
+ Pre and Post unbind protocol events are not fired by the
+ UnBindRequestProcessor.
+ </para>
+ </section>
+
+ <section>
+ <title>Adendum</title>
+
+ <para>
+ In the process of refactoring the protocol module and its processors
+ using message beans from the Common Message API (CMA) we started to
+ use the JNDI provider instead of directly interfacing with the
+ UnifiedBackend.
+ </para>
+
+ <para>
+ There are some issues that arise when using the JNDI provider
+ specifically in the area of translating Exceptions back into
+ LDAPv3 result codes. Some JNDI exceptions are used to represent
+ multiple result codes. Result code to JNDI exception mappings are
+ published <ulink url=
+ "http://java.sun.com/products/jndi/tutorial/ldap/models/exceptions.html">
+ here</ulink> on the SUN Java site. There is no way for the protocol
+ module to tell which result code to use when it encounters an
+ exception that can map to more than one result code. Using the
+ JNDI provider hence results in a loss of resolution. For example
+ the OperationNotSupportedException can represent result codes 12 and
+ 53 for unavailable critical extensions and an unwillingness to
+ perform an operation respectively. Hence when the protocol engine
+ catches a OperationNotSupportedException on calls to the JNDI
+ interfaces there is no way for it to determine the cause of the
+ exception. The protocol engine cannot associate the error with a
+ Control or Extended opertation that is unsupported with a situation
+ that the server implementation specifically does not support like
+ the deletion of a suffix entry. We have solved this problem for the
+ time being by embedding the result code enumeration value into the
+ exception message. Since the result code can range from 1 to 80
+ there are at most 2 digits required to represent it within the
+ message. We use a 4 character prefix which holds the 2 digit result
+ code value surrounded by '[' ']' brackets. When handling exceptions
+ this 4 character prefix is detected if present and the result code
+ is extracted from the exception message. At the present time this
+ is a kludgy solution yet it saves us the hastle of extending JNDI
+ exceptions only to add a result code property to it.
+ </para>
+
+ <para>
+ With the result code situation above we could have taken another
+ approach. The code throwing the exception could store the response
+ code directly in the response by accessing the response being
+ processed. This will spread the code around involved with
+ manipulating or building the response rather than centralizing it.
+ These approaches need to be considered thoroughly before commiting
+ to any one of them. Regardless of the approach the region
+ generating the exception needs to be aware of the result code to
+ associate with the exception. Some of this code is within the JNDI
+ provider, some within the nexus and some deep down within the
+ backends. The only difference with giving access to the response
+ is that we enable its alteration within other modules. There is no
+ way to manadate every peice of code throwing an exception to use
+ whatever mechanism we choose. It would be nice to be able to have a
+ means to enforce it but this is not easy. Nevertheless before
+ sending the response to the encoder the handlers of the protocol
+ module need to detect whether or not the result code was set by the
+ exception handling code in the ldap result of a response. If it did
+ not some default result code would need to be used instead.
+ </para>
+ </section>
+
+</article>
Added: incubator/directory/eve/branches/start/src/docbook/design/request-session-scopes.xml
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/docbook/design/request-session-scopes.xml Thu Jun 24 00:06:35 2004
@@ -0,0 +1,273 @@
+<?xml version="1.0"?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD Simplified DocBook XML V4.1.2.5//EN"
+ "http://www.oasis-open.org/docbook/xml/simple/4.1.2.5/sdocbook.dtd">
+
+<article class="whitepaper">
+ <title>Request and Session Scope Management</title>
+
+ <articleinfo>
+ <author><othername>akarasulu</othername></author>
+ <editor><othername>$Author: bearcej $</othername></editor>
+ <revhistory>
+ <revision>
+ <revnumber>$Revision: 1.2 $</revnumber>
+ <date>$Date: 2003/05/03 01:21:32 $</date>
+ <revdescription>
+ <para>
+$Log: request-session-scopes.xml,v $
+Revision 1.2 2003/05/03 01:21:32 bearcej
+Remove tabs from doc files and fix linefeeds.
+
+Revision 1.1 2003/04/04 01:40:16 akarasulu
+Added more to search operation document yet temporarily suspended it to
+start working on request scope management design which all operations will
+eventually depend upon.
+
+ </para>
+ </revdescription>
+ </revision>
+ </revhistory>
+ </articleinfo>
+
+ <abstract>
+ <para>
+ The management of session and request state requires distinct
+ structures within the server design. Read only and mutable
+ parameters within either scope must be accessed and modified
+ respectively. The server must provide interfaces through which
+ various components within the system uniformally perfrom such
+ operations. These interfaces and access to the objects implementing
+ them the should be centralized and coherent.
+ </para>
+ </abstract>
+
+ <section>
+ <title>Document TODOs:</title>
+ <itemizedlist>
+ <listitem><para>
+ Add diagrams.
+ </para></listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Background</title>
+
+ <para>
+ The ClientManager interface contains methods used to access a
+ client's session object. The ClientManager design promotes
+ centralized access to ClientSession interfaces through a set of
+ methods designed to retrieve the session using a ClientKey or by
+ using the context of the caller's thread. The design standardizes
+ and centralizes access to session data without requiring other
+ server modules to pass around the session object or the client key
+ used to retrieve the session. The design used to manage session
+ scope parameters would offer the same advantages when used to manage
+ access and modify operation on request scope parameters.
+ </para>
+
+ <para>
+ Request information unlike session data changes based on the nature
+ of the protocol operation. For example a search operation will
+ contain a search filter and an add operation will not but will have
+ the new entry to add to the DIT. These differences make it
+ difficult to devise a standard interface to manage request
+ parameters. Using an associative key value pair base Map interface
+ as the basis for the access and storage model standardises the
+ interface across request. However the Map interface compromises
+ security by enabling both access and modification operations on
+ these parameters regardless of whether they are read only or
+ mutable. Use of the Map interface implies weakly typed associations
+ for protocol defined request parameters. The types of parameters
+ are implicit when accessed or altered as objects in a Map. Strong
+ explicit types for predefined request parameters should be used if
+ we know the type. Weak type associations with a Map should only be
+ used for user defined request parameters that are not predefined.
+ </para>
+
+ <para>
+ The request specific processors within the ProtocolEngine are
+ responsible for extracting request parameter from a request PDU
+ demarshalled LDAPMessage envelope. The envelope class is a
+ Java stub class generated by the Snacc ASN.1 compiler. By leaving
+ parameter extraction up to the processor, the current design
+ increases the coupling between parameter extraction and request
+ processing which could be two completely separate phases. The high
+ degree of coupling imposes a dependency on Snacc API's within the
+ ProtocolEngine. The only two modules within the server which should
+ have these dependencies are the Encoder and Decoder modules. It
+ makes sense to localize parameter extraction from a request PDU
+ within the decoder module to spare the protocol engine. The
+ demarshaling from BER encoded streams handled in the Decoder module
+ should be followed by parameter extraction into a standard request
+ object independent of the ASN.1 BER library used. The protocol
+ engine's processors only process requests using these agnostic
+ request objects without Snacc dependencies, they are not responsible
+ for managing the creation of the request. The design extrapolated
+ to the response phase would require a response object for the
+ respective request object (if required by the protocol). The
+ packaging of response parameters into the Snacc specific LDAPMessage
+ envelope would then be delegated to the Encoder which is already
+ dependant on Snacc APIs. The localization of all ASN.1 dependencies
+ to the Decoder and the Encoder module implementations, makes
+ switching ASN.1 libraries easier by only requiring the Encoder and
+ Decoder module implementations to be swapped out without affecting
+ the ProtocolEngine.
+ </para>
+
+ <para>
+ The interfaces for these Snacc independant request and response
+ objects should be kept within the common subproject so both clients
+ and the server can access them. Final concrete implementations
+ should reside within the package holding BER library dependant
+ classes used to extract these parameters or add them to the BER
+ library specific envelope. Within there BER library specific
+ packages the implemenation objects would expose package friendly
+ methods to build and modify read-only parameters thereby preserving
+ secure access and modification to critical protocol mandated request
+ and response parameters. Utility classes used to build or extract
+ response and request parameters from message envelopes composed of
+ ASN.1 compiler generated Java stub classes, needs not reside within
+ the server subproject. These BER library dependant clases will be
+ used by both clients and server Encoder/Decoder module
+ implementations and hence are shared across subprojects. They are
+ best kept within the common subproject close to the BER library
+ dependant stubs which they operate upon.
+ </para>
+
+ <para>
+ The design goal to standardize request and response scope
+ parameter handling leads to several architectural benefits. The
+ benefits and drawbackes are itemized below:
+ </para>
+
+ <itemizedlist>
+ <title>Benefits</title>
+
+ <listitem><para>
+ Centralized acess to request and response parameters.
+ </para></listitem>
+
+ <listitem><para>
+ Standard type explict accessors and mutators of request parameters.
+ </para></listitem>
+
+ <listitem><para>
+ Data encapsulation with secure accessor and mutator visibility.
+ </para></listitem>
+
+ <listitem><para>
+ Diminished dependence on specific (Snacc) BER libraries used.
+ </para></listitem>
+
+ <listitem><para>
+ Clear distinction between the role of processors and request
+ or response value objects.
+ </para></listitem>
+
+ <listitem><para>
+ Greater potential for code reuse across clients and server modules.
+ </para></listitem>
+
+ <listitem><para>
+ Clear, distinct and isolated facility dedicated to request scope
+ management.
+ </para></listitem>
+
+ <listitem><para>
+ Generally adds more flexibility to the architecture while making it
+ more coherent.
+ </para></listitem>
+
+ <listitem><para>
+ Enables potential later for processor pooling rather than
+ instantiation for each request. May not really be worth that much
+ since processor creation is not expensive.
+ </para></listitem>
+ </itemizedlist>
+
+
+ <itemizedlist>
+ <title>Drawbacks</title>
+
+ <listitem><para>
+ Requires additional interfaces and classes within the common
+ subproject.
+ </para></listitem>
+
+ <listitem><para>
+ Requires changes to the ClientModule, EncoderModule,
+ DecoderModule and the ProtocolModule along with a rewrite of the
+ request processors. SEDA stage events will also need
+ modification to use these objects instead of the LDAPMessage
+ wrapper generated by Snacc.
+ </para></listitem>
+
+ <listitem><para>
+ Adds the runtime time and space overhead of copying parameters
+ into the agnostic request and response objects. This will be
+ ameliorated by removing this functionality from the processors.
+ </para></listitem>
+
+ <listitem><para>
+ More work and more code.
+ </para></listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Design</title>
+
+ <para>
+ An extra package has been created for LDAPv3 operation value object
+ interfaces which represent requests and responses. We'll begin by
+ defining these interfaces within the package org.apache.ldap.common.ops. A
+ single package rather than one for responses and another for
+ requests was chosen to minimize the package import statements of
+ dependent code.
+ </para>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+ </section>
+
+ <section>
+ <title>Implementation</title>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+ </section>
+
+ <section>
+ <title>Future</title>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+ </section>
+
+ <section>
+ <title>Faults</title>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+ </section>
+
+</article>
Added: incubator/directory/eve/branches/start/src/docbook/design/rootdse-design.xml
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/docbook/design/rootdse-design.xml Thu Jun 24 00:06:35 2004
@@ -0,0 +1,90 @@
+<?xml version="1.0"?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD Simplified DocBook XML V4.1.2.5//EN"
+ "http://www.oasis-open.org/docbook/xml/simple/4.1.2.5/sdocbook.dtd">
+
+<article class="whitepaper">
+ <title>Module Implementation</title>
+
+ <articleinfo>
+ <author><othername>akarasulu</othername></author>
+ <editor><othername>$Author: bearcej $</othername></editor>
+ <revhistory>
+ <revision>
+ <revnumber>$Revision: 1.3 $</revnumber>
+ <date>$Date: 2003/05/03 01:21:32 $</date>
+ <revdescription>
+ <para>
+$Log: rootdse-design.xml,v $
+Revision 1.3 2003/05/03 01:21:32 bearcej
+Remove tabs from doc files and fix linefeeds.
+
+Revision 1.2 2003/03/23 13:24:46 akarasulu
+Added these files from the ALPHA-0_7 branch.
+
+Revision 1.1.2.1 2003/03/10 23:24:22 akarasulu
+Moved design documentation from docs/design to src/docbook/design.
+
+Revision 1.1.2.1 2003/03/03 04:53:51 akarasulu
+backend.xml will be backend-module.xml and rootdse-design.xml will have
+stuff in html file moved into it.
+
+Revision 1.1.2.1 2003/03/03 04:49:25 akarasulu
+Added as placeholders for now.
+
+ </para>
+ </revdescription>
+ </revision>
+ </revhistory>
+ </articleinfo>
+
+ <abstract>
+ <para>
+ </para>
+ </abstract>
+
+ <section>
+ <title>Document TODOs:</title>
+ <itemizedlist>
+ <listitem><para>
+ Add diagrams.
+ </para></listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Implementation</title>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+ </section>
+
+ <section>
+ <title>Future</title>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+ </section>
+
+ <section>
+ <title>Faults</title>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+ </section>
+
+</article>
Added: incubator/directory/eve/branches/start/src/docbook/design/schema-module.xml
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/docbook/design/schema-module.xml Thu Jun 24 00:06:35 2004
@@ -0,0 +1,594 @@
+<?xml version="1.0"?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD Simplified DocBook XML V4.1.2.5//EN"
+ "http://www.oasis-open.org/docbook/xml/simple/4.1.2.5/sdocbook.dtd">
+
+<article class="whitepaper">
+ <title>Module Implementation</title>
+
+ <articleinfo>
+ <author><othername>akarasulu</othername></author>
+ <editor><othername>$Author: bearcej $</othername></editor>
+ <revhistory>
+ <revision>
+ <revnumber>$Revision: 1.6 $</revnumber>
+ <date>$Date: 2003/05/03 01:45:23 $</date>
+ <revdescription>
+ <para>
+$Log: schema-module.xml,v $
+Revision 1.6 2003/05/03 01:45:23 bearcej
+Refix image URLs
+
+Revision 1.5 2003/05/03 01:43:08 bearcej
+Add maven file to help generate server site.
+Modify graphic links again.
+Remove tabs from doc files and fix linefeeds.
+
+Revision 1.4 2003/05/03 01:21:32 bearcej
+Remove tabs from doc files and fix linefeeds.
+
+Revision 1.3 2003/04/08 02:29:55 bearcej
+* Clean up project.properties
+* Fix logos in project.xml
+* Fix links to image files in docs
+
+Revision 1.2 2003/03/23 13:24:46 akarasulu
+Added these files from the ALPHA-0_7 branch.
+
+Revision 1.1.2.3 2003/03/15 17:24:14 bearcej
+Fixed figure tags to conform to simple docbook.
+Modified Files:
+ Tag: ALPHA-0_7
+ schema-module.xml
+
+Revision 1.1.2.2 2003/03/10 23:43:33 akarasulu
+Moved links so that image references point to /image/design. Note that
+references do not have a [.] in front since the maven driven transforms
+automatically append [.] to references.
+
+Revision 1.1.2.1 2003/03/10 23:24:22 akarasulu
+Moved design documentation from docs/design to src/docbook/design.
+
+Revision 1.1.2.3 2003/03/09 21:50:26 akarasulu
+Ok the schema documentation is done.
+
+Revision 1.1.2.2 2003/03/09 04:59:15 akarasulu
+Checking in a start to the schema manager documentation.
+
+Revision 1.1.2.1 2003/03/03 04:49:25 akarasulu
+Added as placeholders for now.
+
+ </para>
+ </revdescription>
+ </revision>
+ </revhistory>
+ </articleinfo>
+
+ <abstract>
+ <para>
+ The purpose of the SchemaModule is to parse the various published
+ schema files storing their contents in a form suitable for answering
+ schema related questions. Schema checking, value normalization and
+ filter processing as well as most fundamental backend operations
+ require schema knowledge.
+ </para>
+ </abstract>
+
+ <section>
+ <title>Document TODOs:</title>
+ <itemizedlist>
+ <listitem><para>
+ Add diagrams.
+ </para></listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Architecture</title>
+
+ <section>
+ <title>Brief Overview of Schema Operations</title>
+
+ <para>
+ Schema information is critical within the server for schema
+ checking, value normalization, searching and syntax checking.
+ To define how the SchemaModule or any SchemaManager
+ implementation is to be designed we must first define how these
+ aspects relate to servicing protocol requests.
+ </para>
+
+ <para>
+ Schema's define a set of objectclasses, attributes, syntaxes
+ and matching rules. Schema checking in general can be defined
+ as applying constraints imposed by these definitions. For
+ example attribute values are constrained with respect to their
+ syntax and cardinality. Entries for example will be constrained
+ to include the MUST list of attributes in order to conform to
+ the objectclasses they implement and so on. Schema checking is
+ applied by default. If you attempt to add unknown attributes to
+ an entry whose objectclasses do not allow, the operation will
+ not be permitted by the server. Likewise, an attempt to add a
+ String valued attribute which is defined to only support numeric
+ values will not be permitted. This is what we mean by schema
+ checking. The server hence uses these definitions to constrain
+ entries and the values of their attributes, rejecting any
+ operation that would violate the imposed constraints.
+ </para>
+
+ <para>
+ Value normalization is critical for correctly searching the
+ directory. When entries are added to the directory the values
+ of their attributes are stored and returned in the format they
+ were provided preserving both whitespace and case. However when
+ users attempt to search the directory they provide search
+ filters with attribute value assertions like (cn=James Brown).
+ The entry that we intend to recall may have had the cn attribute
+ set as " james BROWN". Because the original user provided cn
+ was entered in a different case with several spaces between the
+ two parts of the full name, the match will not occur and the
+ intended entry will not be returned. Failure to retrieve the
+ entry would be the case if value normalization were not used.
+ Fortunately, value normalization has been implemented yet it
+ requires attribute schema definitions for correct operation.
+ LDAP has defined the concept of a matching rule specifically to
+ assist in value normalization. The matching rule for an
+ attribute defines how values of that attribute are to be
+ compared. In the case of the cn example above, the matching
+ rule defined for the attribute is called caseIgnoreMatch. With
+ this knowledge the server generates normalized keys for matching
+ attributes based on the matching rule. For the original user
+ provided cn value of " james BROWN" the server will create a
+ normalized key of "james brown". Since the attribute type is
+ case indifferent, its safe to arbitarily (yet consistantly)
+ generate keys in one case only. Also notice that several spaces
+ in between the two names were consolidated into one space and
+ spaces at either ends of the string were stripped off. This
+ type of white space normalization preserves value tokenization
+ while removing unnecessary whitespace. We call the operation a
+ deep trim as opposed to a superficial trim that removes
+ whitespace at both ends only. Unlike simple trims which leave
+ inner stretches of whitespace, a deep trim, condenses inner
+ whitespace regions into a single space. When another directory
+ user tries to search the directory specifically looking for the
+ James Brown example entry with the filter (cn=James Brown), the
+ filter attribute values are automatically normalized based on
+ the matching rules of schema definitions. The effective
+ normalized filter would then be (cn=james brown). The value of
+ the cn filter assertion is compared against the normalized user
+ provided cn value of the entry to produce a match and return the
+ correct candidate entry. Without the use of matching rules
+ defined in schema definitions, correct normalization would not
+ be possible resulting in a highly input sensitive directory
+ server.
+ </para>
+
+ <para>
+ Syntax checking is the process of validating correct values for
+ attributes. Attributes will need to be constrained according to
+ format, type and size. Syntaxes define the manner in which
+ attribute values should be checked for validity. Again these
+ rules are defined within published schemas to constrain possible
+ values. Examples of syntaxes are Boolean whose IANA assigned
+ public object identifier (OID) is 1.3.6.1.4.1.1466.115.121.1.7.
+ Boolean attributes can only have values of "TRUE" or "FALSE".
+ Any other value for attribute types with this syntax will result
+ in a schema violation - the server will reject any operation
+ resulting in this violation.
+ </para>
+
+ <para>
+ LDAP searches must take into account attribute inheritance.
+ When a search with a filter of (name=abc) is conducted it should
+ return all entries with attributes derived from name. Meaning
+ entries where cn or sn equal "abc" should be returned. The name
+ attribute is the least specific base for cn and sn which derive
+ from name. Attribute inheritance trees are defined within the
+ schema. Without this schema information correct matching cannot
+ occur as specified by the protocol.
+ </para>
+ </section>
+
+ <section>
+ <title>The LDAP Schema Dilema</title>
+
+ <para>
+ LDAP defines the concept of a RootDSE entry. The RootDSE entry
+ is where several attributes specific to the directory server or
+ Directory Server Agent (DSA) are stored. The RootDSE stands for
+ the root DSA Specific Entry (DSE). It holds for example the
+ location of a set of replica servers that can be contacted in
+ case this server is unavailable or unable to service requests
+ due to heavy load. One of the attributes contained within the
+ RootDSE is the subschemasubentry attribute. All entries in an
+ LDAP server can contain what is known as the subentrysubschema
+ attribute. The attribute is intended to point to or refer to a
+ local entry which stores amongst other things the schema
+ definitions constraining the refering entry. The
+ subschemasubentry attribute is single valued so the RootDSE and
+ any other regular entry can only contain a single value for it.
+ This makes sense since an entry should be governed by only one
+ schema. If more than one set of schema definitions governed the
+ composition of an entry inconsistant definitions could occur.
+ </para>
+
+ <para>
+ The intention of having a subschemasubentry within the RootDSE
+ was to enable the discovery of the governing directory schema.
+ This implies a one to one relationship between a schema and a
+ directory server. In fact most LDAPv3 servers manage a single
+ common schema for the entire Directory Information Tree (DIT) of
+ the server. It is a common practice to use cn=schema for the
+ value of the subschemasubentry. Novell's NDS and the Netscape
+ Directory Server (a.k.a. SUN One Directory Server) store schema
+ definitions in this entry with a DN of cn=schema. Serveral
+ other commercial servers do the same.
+ </para>
+
+ <para>
+ This is a very limiting aspect to LDAP. The explosion of
+ published schemas stuffed into the cn=schema entry has conjested
+ the entry with attributes for objectclasses, attribute
+ definitions and syntaxes not to mention ACI attributes that are
+ also injected into the entry. Pulling down the massive entry
+ takes far too long incomparison to the average sized entries in
+ the DIT. Sure filters can be used to bring down subsets of the
+ entry as needed, however this does not resolve the problem fully
+ since several values for attributes exist and entire definition
+ bodies are embedded within these values as large text objects.
+ Such selective filters on the entry still need to use substring
+ matching which is the least efficient and accurate manner for
+ searching the entry other than using the approximate search
+ operator. Overall the cn=schema entry is massive with hundreds
+ if not thousands of attributes, and it is very difficult to
+ search the contents of this entry efficiently and accurately to
+ answer schema related questions.
+ </para>
+
+ <para>
+ Another limitation imposed by storing all schema information in
+ one place is the implication that only one schema governs the
+ composition of all entries within the directory. The need to
+ constrain different regions of the tree through the definition
+ of alternative schemas will inevitably arise. It is very
+ unreasonable to consolidate and limit all schema definitions to
+ one. What's the point of having the potential for every entry
+ to contain a subschemasubentry attribute? Why enable the
+ attribute in every entry if there can only be one schema defined
+ for the entire DIT? By convention, the entry referred to by the
+ DN value stored in the RootDSE's subschemasubentry attribute
+ could be implied as the one place for the storage of schema
+ definitions, since only one schema governs the entire directory.
+ This contradiction leads us to believe that the protocol at its
+ inception borrowed too little from its more robust parent, the
+ X.500 directory. The subschemasubentry concept made its way
+ into LDAP but not fully. This is why LDAP servers do not
+ provide the ability to manage multiple regions governed by
+ different schema definations. They do however provide the
+ ability to have different entries point to multiple schemas by
+ allowing all to have a subschemasubentry attribute.
+ </para>
+
+ <para>
+ LDAP never clearly defined a means to managing schema data in
+ separate regions of the directory tree - this was left up to the
+ server implementation if supported at all. The notion of
+ partitioning the directory tree into regions managed by
+ different schemas was very explicitly defined by the X.500
+ standard in what they called Subschema Authoritative Areas or
+ SAAs. These regions were defined at various points in the
+ DIT to mandate schema constraints. The coverage of the area
+ was defined using a subtree specification and SAAs could be
+ located anywhere and occupy any subtree shape imaginable based
+ on the parameters of the specification. Unlike X.500 LDAP lacks
+ these rich constructs.
+ </para>
+
+ <para>
+ While designing the SchemaManager service we kept these short
+ falls in mind with the intention of alleviating them if not
+ irradicating them. The need to enable multiple schemas
+ restricted to specific regions of the DIT was too compelling to
+ ignore. At a bare minimum we wanted to enable different schemas
+ for DIT partitions or in otherwords backends of the server while
+ remaining protocol compliant giving users the same environment
+ they are accostomed to. Our attempt to do so is incomplete and
+ an ongoing process. Before the protocol compliant alpha
+ release we would like to enable a super schema entry at
+ cn=schema for default schema support in the expected fashion. We
+ would also like to enable each backend to have its own schema
+ for the time being until a more complete mechanism for schema
+ management can be established. While stuck in this limbo, we
+ can investigate further constructs and mechanisms within X.500
+ which can be incorporated into the server while remaining in
+ full compliance with the LDAPv3 specifications. The design
+ described for now regarding the SchemaManager and its associated
+ helper interfaces is mostly an intermediate design.
+ </para>
+
+ <para>
+ Rather than implement full blown SAAs we decided to borrow a
+ little from them. We simply assigned an SAA to a DN and
+ considered the subtree of the SAA to encompass everything below
+ it. In the end we fell back on just requiring an SAA to be
+ defined for every naming context or backend suffix to be
+ attached to the server. Hence every backend in the server must
+ have its own set of schema definitions. Was this the correct
+ way to proceed? Probably not! But it was done and for the time
+ being it will stay until we refactor the design into a more
+ accurate one. Also note that for the time being no schema entry
+ referred to by the subschemasubentry exists at the present time,
+ so even though schemas are applied one for each backend, they
+ nor the superset of them are published to the outside world.
+ With these facts noted we shall continue in the next section to
+ describe the interfaces within the schema package.
+ </para>
+ </section>
+
+ <section>
+ <title>
+ SchemaManager Service Interface And Its Associated Helpers
+ </title>
+
+ <para>
+ The SchemaModule implements the SchemaManager service interface
+ which declares two methods to access a Schema object:
+ getSchema() and getCompleteSchema(). The getSchema() method,
+ requires a String argument specifying a distinguished name. As
+ a consequence of having implementations possibly parse the
+ String DN argument into a Name, getSchema() throws a
+ NamingException. As can be inferred getSchema() retrieves the
+ Schema instance in effect at a point (or entry) within the
+ directory specified by DN. The returned schema is the schema
+ defined by the SAA at that suffix DN. The other method,
+ getCompleteSchema() retrieves the union of all the schema object
+ definitions within the entire directory as one Schema instance.
+ The returned Schema representing the superset of schema
+ definitions would be equivalent to the content stored by a
+ cn=schema entry if one existed.
+ </para>
+
+ <para>
+ The role of the SchemaManager service is simple. It is a
+ location specific Schema factory. The Schema interface is the
+ contract through which answers to schema related questions are
+ obtained.
+ </para>
+
+ <para>
+ Every aspect with regard to the effective schema constraining
+ a point in the directory can be assertained by methods on the
+ Schema interface. These methods enable most of the schema
+ operations required for syntax checking, attribute value
+ normalization, and schema checking to detect object class
+ violations. Access to other interfaces are provided to perform
+ these operations via the Schema.
+ </para>
+
+ <para>
+ The Schema interface enables access to two types of NameParsers
+ used to parse a String representation of a DN into a Name. The
+ getNameParser() method returns a NameParser that does not
+ normalize name component attribute identifiers or their values.
+ The getNormalizingParser() method returns a NameParser that does
+ normalize attribute identifiers and values based on the
+ attribute definitions in the Schema instance returning the
+ parser. Note that for each name component attribute value pair
+ within a distinguished name a different normalization function
+ may need to be applied. The normalizing name parser must lookup
+ the normalizer to use for each of the component attributes. Of
+ course this information is available within the Schema that
+ creates the normalizing name parser.
+ </para>
+
+ <para>
+ Access is also provided to an LdifParser and an LdifComposer.
+ These interfaces define methods for taking a MultiMap to and
+ from an LDIF representation. A MultiMap is a extention on the
+ Map interface to allow a single key to have multiple values
+ defined for it. It is ideal for storing attribute values since
+ attributes can have a single value or have multiple values. The
+ MultiMap interface is defined within the Apache Commons
+ Collections package.
+ </para>
+
+ <para>
+ Another interface accessible through the Schema.getNormalizer()
+ method is Normalizer. Normalizers are attribute specific. They
+ transform the values of String attributes according to the
+ matching rules defined for them. For example some default
+ normalizers for case insensitive Strings attributes are defined
+ to do a deepTrimToLower and others that are for case sensitive
+ Strings may perform a deepTrim without transforming alpha
+ characters into lower case.
+ </para>
+
+ <para>
+ The Schema interface itself defines several other methods that
+ test, or transform values of a specific attribute type. Another
+ Schema method is provided to apply a syntax check on an entire
+ entry.
+ </para>
+ </section>
+ </section>
+
+ <section>
+ <title>Implementation</title>
+
+ <section>
+ <title>Schema Files</title>
+
+ <para>
+ Presently, schema definitions are stored in schema files. These
+ static ascii files use the standard <ulink url=
+ "http://ldap.akbkhome.com/attribute/attributeTypes.html">
+ Attribute Type Description </ulink> and <ulink url=
+ "http://ldap.akbkhome.com/attribute/objectClasses.html">Object
+ Class Description</ulink> syntax as specified within <ulink url=
+ "http://www.faqs.org/rfcs/rfc2252.html"> RFC2252</ulink>. They
+ are slightly modified to facilitate parsing ease by prefixing
+ the descriptions with either a 'attributetype' or 'objectclass'
+ marker. The format as well as the various files used were
+ adopted from the definitions managed by the <ulink url=
+ "http://openldap.org">OpenLdap</ulink> effort.
+ </para>
+
+ <para>
+ The definitations are categorically separated into separate
+ files one for each major group of definitions. For example the
+ core set of definitions in RFC2252 are resident in a schema file
+ named core.schema. Other popular and published type
+ descriptions exist like the java schema and the corba support
+ schema. The contents of these files are parsed and stored in
+ AttributeSpec and ObjectClassSpec beans.
+ </para>
+ </section>
+
+ <section>
+ <title>Initialization Time</title>
+
+ <para>
+ The SchemaModule creates various Schema instances as a
+ consequence of initialization. These Schema objects are
+ accessible using a DN. Their contents are based on the
+ contents of the parsed schema files and the SchemaManaqer's
+ configuration section within the config.xml file. The
+ configuration for the SchemaManager specifies the set of schema
+ files that can be used to define SAAs. The files are referred
+ to within schema elements which assigns a schema name to the
+ file. At configuration time the very first task performed is
+ the parse of these files. For each file a Schema object is
+ populated with AttributeSpec and ObjectClassSpec objects. While
+ filling the target Schema object, a superset Schema object
+ returned using the getCompleteSchema() method, is populated as
+ well. The complete schema not only fulfills the needs for a
+ complete schema hangling off of the cn=schema entry, but also
+ allows for cross referencing between schema files. Sometimes
+ an attribute or objectclass is defined using existing core
+ schema attributes and objectclasses. Resolution of values using
+ parent objectclasses and attributes is made possible by this
+ complete union schema of all schema definitions stored accross
+ these files.
+ </para>
+
+ <para>
+ Once all schema files are parsed a normalization configuration
+ element section is used to construct Normalizers for the various
+ matching rules the server must implement. Next a configuration
+ section for user defined syntax checkers is used to create
+ syntax mandating elements used by the schema to check attribute
+ values for correct syntax usage. Finally once all schema
+ objects have been populated with their specification beans,
+ required normalizers and syntax checkers the SAAs of the
+ configuration are created.
+ </para>
+
+ <para>
+ SAA elements define the set of schema object that are valid
+ below and at a point within the directory. Every descendent
+ entry at and under the SAA DN will be constrained by the set
+ of schema objects defined. The SAA element contains a set of
+ references to the schema files parsed. For each SAA element a
+ new Schema implementation is instantiated and populated with the
+ AttributeSpec beans, ObjectClassSpec beans, Normalizers and
+ syntax checkers of the reference Schema objects. Hence an SAA
+ is just another Schema that is the union of several schema file
+ Schemas.
+ </para>
+ </section>
+
+ <section>
+ <title>Runtime</title>
+
+ <para>
+ At runtime several Maps within the SchemaImpl instances are
+ already populated. These set of Maps are used to do fast
+ lookups to access AttributeSpecs, ObjectClassSpecs, Normalizers
+ and SyntaxCheckers. The various methods on the Schema interface
+ are implemented using these Maps within the SchemaImpl class.
+ </para>
+ </section>
+
+ </section>
+
+ <section>
+ <title>Future</title>
+
+ <para>
+ Eventually we would like to solve the schema dilema for LDAP
+ elegantly without breaking with protocol requirements. No matter
+ what the same referrence to the superset of schema elements must be
+ maintained within the entry referred to by the subschemasubentry
+ attribute in the RootDSE. At the present moment we have delayed the
+ implementation of this schema administration entry. It must at some
+ point be implemented to comply with the standard mode of schema
+ inquire to be familiar to users. However nothing is stopping us
+ form making this entry the suffix to an entire backend under which
+ other entries can reside to yeild specific information in a
+ searchable format concerning schema objects and SAAs. For example
+ if we were to use cn=schema as the value for the subschemasubentry
+ attribute within the RootDSE, then cn=schema can be the suffix of
+ a backend with entries below.
+ </para>
+
+ <para>
+ At the present time we do not have a clear understanding of exactly
+ how we intend to structure this tree. We do know that we want to
+ enable the decomposition of attribute type and objectclass
+ descriptions into searchable entries. A special schema can be
+ defined to store schema information itself. This way the search
+ machinery of the backend can be used to answer complicated questions
+ regarding attribute and objectclass relationships in a standard way.
+ Otherwise we will have to devise Maps within the Schema
+ implementation to correlate descriptions with one another. We would
+ also like to search descriptions and SAA specifications without
+ requiring clients to parse their syntactic representation. Breaking
+ these specifications down into entries solves these problems. While
+ supporting these extra features to aid in schema support we would
+ like to provide the expected constructs for backwards compatability.
+ Eventually we hope that we can persuade the LDAP community to see
+ the value proposition of schema descriptions specified as entries
+ with a deep schema administration context rooted at cn=schema or
+ what ever is specified by the subschemasubentry within the RootDSE.
+ </para>
+
+ <para>
+ Just for fun we envisioned the following DIT structure to a schema
+ administration context. The diagram below represents the DIT.
+ Imagine for a moment that cn=schema were the root of the schema
+ administration naming context. Under it would reside containers
+ for entries describing attribute types, objectclasses, syntaxes,
+ and matching rules. Also located under cn=schema could reside SAA
+ specification describing the subtree of authority and a schema
+ definition set of the schema objects composing the SAA. Questions
+ as to which SAA governs the schema of an entry can be used in a
+ filter to search for the appropriate SAA in charge. Hence the
+ effective subschemasubentry value if asked for of an entry can be
+ extracted at entry retrival time by searching the ou=SAA branch.
+ </para>
+
+ <figure>
+ <title>Speculation on a Administrative Schema DIT Structure</title>
+ <graphic fileref="../images/AdminSchemaContext.gif"/>
+ </figure>
+ </section>
+
+ <section>
+ <title>Faults</title>
+
+ <para>
+ Incomplete since the RootDSE subschemasubentry attribute referral to
+ a schema description entry does not exist. We need a cn=schema
+ entry to present attributeType and objectClasses attributes in the
+ proper expected syntax.
+ </para>
+
+ <para>
+ Messy adhoc implementation with maps all over the place.
+ </para>
+
+ <para>
+ The inheritance thing does not work and there are a number of
+ bugs where cross schema references do not resolve.
+ </para>
+ </section>
+
+</article>
Added: incubator/directory/eve/branches/start/src/docbook/design/seda-implementation.xml
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/docbook/design/seda-implementation.xml Thu Jun 24 00:06:35 2004
@@ -0,0 +1,86 @@
+<?xml version="1.0"?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD Simplified DocBook XML V4.1.2.5//EN"
+ "http://www.oasis-open.org/docbook/xml/simple/4.1.2.5/sdocbook.dtd">
+
+<article class="whitepaper">
+ <title>Module Implementation</title>
+
+ <articleinfo>
+ <author><othername>akarasulu</othername></author>
+ <editor><othername>$Author: bearcej $</othername></editor>
+ <revhistory>
+ <revision>
+ <revnumber>$Revision: 1.3 $</revnumber>
+ <date>$Date: 2003/05/03 01:21:32 $</date>
+ <revdescription>
+ <para>
+$Log: seda-implementation.xml,v $
+Revision 1.3 2003/05/03 01:21:32 bearcej
+Remove tabs from doc files and fix linefeeds.
+
+Revision 1.2 2003/03/23 13:24:46 akarasulu
+Added these files from the ALPHA-0_7 branch.
+
+Revision 1.1.2.1 2003/03/10 23:24:22 akarasulu
+Moved design documentation from docs/design to src/docbook/design.
+
+Revision 1.1.2.1 2003/03/03 04:49:25 akarasulu
+Added as placeholders for now.
+
+ </para>
+ </revdescription>
+ </revision>
+ </revhistory>
+ </articleinfo>
+
+ <abstract>
+ <para>
+ </para>
+ </abstract>
+
+ <section>
+ <title>Document TODOs:</title>
+ <itemizedlist>
+ <listitem><para>
+ Add diagrams.
+ </para></listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Implementation</title>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+ </section>
+
+ <section>
+ <title>Future</title>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+ </section>
+
+ <section>
+ <title>Faults</title>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+
+ <para>
+ </para>
+ </section>
+
+</article>
Added: incubator/directory/eve/branches/start/src/docbook/design/server-architecture.xml
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/docbook/design/server-architecture.xml Thu Jun 24 00:06:35 2004
@@ -0,0 +1,613 @@
+<?xml version="1.0"?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD Simplified DocBook XML V4.1.2.5//EN"
+ "http://www.oasis-open.org/docbook/xml/simple/4.1.2.5/sdocbook.dtd">
+
+<article class="whitepaper">
+ <title>Server Architecture</title>
+
+ <articleinfo>
+ <author><othername>akarasulu</othername></author>
+ <editor><othername>$Author: bearcej $</othername></editor>
+ <revhistory>
+ <revision>
+ <revnumber>$Revision: 1.4 $</revnumber>
+ <date>$Date: 2003/05/03 01:21:32 $</date>
+ <revdescription>
+ <para>
+$Log: server-architecture.xml,v $
+Revision 1.4 2003/05/03 01:21:32 bearcej
+Remove tabs from doc files and fix linefeeds.
+
+Revision 1.3 2003/04/21 21:11:50 bearcej
+
+* Fix broken links in documentation.
+
+Revision 1.2 2003/03/23 13:24:46 akarasulu
+Added these files from the ALPHA-0_7 branch.
+
+Revision 1.1.2.3 2003/03/15 17:21:58 bearcej
+Fixed abstract tag.
+Modified Files:
+ Tag: ALPHA-0_7
+ server-architecture.xml
+
+Revision 1.1.2.2 2003/03/10 23:43:33 akarasulu
+Moved links so that image references point to /image/design. Note that
+references do not have a [.] in front since the maven driven transforms
+automatically append [.] to references.
+
+Revision 1.1.2.1 2003/03/10 23:24:22 akarasulu
+Moved design documentation from docs/design to src/docbook/design.
+
+Revision 1.1.2.9 2003/03/02 00:37:32 akarasulu
+Adjusting spacing.
+
+Revision 1.1.2.8 2003/03/02 00:32:39 akarasulu
+Completed listener documentation but needs some work and added the article
+info tag to both these document. Also flaged these docs as whitepapers.
+
+ </para>
+ </revdescription>
+ </revision>
+ </revhistory>
+ </articleinfo>
+
+ <abstract>
+ <para>
+ The server consists of a set of loosely coupled modules. All server
+ modules are not created equally. Some modules are stages that take
+ part in the Staged Event Driven Architecture (SEDA) aspect of the
+ LDAPd server. Some modules are startable, having a single driver thread.
+ The simplest modules have no driver at all relying on the threads
+ of caller modules to drive their workload. This document describes the
+ modular structure of the server without delving deep into each specific
+ module, but rather defining what a module is, and the various types of
+ modules within the server. Other documents are dedicated to the
+ implementation of each specific module.
+ </para>
+ </abstract>
+
+ <section>
+ <title>What is a Module?</title>
+
+ <para>
+ LDAPd is composed of modules, but what exactly is a module? The
+ definition is partly defined by the LDAPd project and partly defined
+ by the Avalon Framework. Avalon defines lifecycle methods for
+ components that fit into a framework. Components define interfaces
+ used to manage lifecycle operations. These lifecycle aspects are
+ then automatically managed by a component conatiner using the
+ Inversion of Control Pattern. Inversion of Control enables the
+ construction of reusable loosely coupled components. Avalon
+ Framework specifies the various lifecycle methods using interfaces
+ that components may have. The framework is just that, an API mostly
+ composed of interfaces. The designers of Avalon have thought of
+ all the possible generalized lifecycle methods, components may have
+ and have forged a set of interfaces for component designers to use.
+ </para>
+
+ <para>
+ The concept of an LDAPd module is defined in terms of Avalon
+ Framework interfaces. In terms of lifecycle behavoirs, an LDAPd
+ module is a log enabled, configurable, initializable, startable,
+ and coincidentally, stopable, thread safe component with potential
+ dependencies on other components within the server. The Avalon
+ Framework interfaces and their methods define these lifecycle
+ behavoirs. We have programatically defined an LDAPd module as an
+ interface that extends many Avalon Framework interfaces. Not
+ surprisingly, the name of the interface is Module and it is located
+ in the org.apache.eve package. All LDAPd modules must implement this
+ interface. The Module interface simply states the lifecycle methods
+ a module must implement. The set of Avalon Framework interface's
+ extended by the Module interface are listed below:
+ </para>
+
+ <itemizedlist>
+ <listitem><para>Startable</para></listitem>
+ <listitem><para>ThreadSafe</para></listitem>
+ <listitem><para>LogEnabled</para></listitem>
+ <listitem><para>Serviceable</para></listitem>
+ <listitem><para>Configurable</para></listitem>
+ <listitem><para>Contextualizable</para></listitem>
+ <listitem><para>Initializable</para></listitem>
+ </itemizedlist>
+
+ <para>
+ Besides mandating the lifecycle functions, the Module interface
+ also defines extra methods used to query information regarding the
+ role, name and implementation of a Module. More than one module
+ implementation can exist for a module service type, and the specific
+ implementation chosen can be delayed until runtime. Besides the
+ Module interface, a base AbstractModule class is defined as an
+ adapter which correctly handles most of the lifecycle methods of a
+ module. Subclasses of AbstractModule are expected to implement
+ some criticle and highly specific interface methods to be concrete.
+ </para>
+ </section>
+
+ <section>
+ <title>Core Service Interfaces</title>
+
+ <para>
+ Building a module for the sake of implementing the required
+ lifecycle interfaces does not make sense. A module needs to do
+ something by providing a service. The Avalon Framework defines the
+ concept of a service interface for components. Publicly exposed
+ service interfaces provide methods that callers invoke to interact
+ with the service. The service interface in this way defines the
+ role of the module within the server. The service interfaces are
+ completely decoupled and independant of the lifecycle methods.
+ </para>
+
+ <para>
+ LDAPd defines a set of core service interfaces which must be
+ implemented as server modules. These are the set of manditory
+ services required to make the server work. These services are
+ listed below:
+ </para>
+
+ <table frame='all'><title>Mandarory LDAPd Services</title>
+ <tgroup cols='3' align='left' colsep='1' rowsep='1'>
+ <colspec colname='Interface'/>
+ <colspec colname='Package'/>
+ <colspec colname='Description'/>
+ <thead>
+ <row>
+ <entry>Service Interface</entry>
+ <entry>Java Package</entry>
+ <entry>Service Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>UnifiedBackend</entry>
+ <entry>org.apache.eve.backend</entry>
+ <entry>The junction where all backends connect.</entry>
+ </row>
+ <row>
+ <entry>ClientManager</entry>
+ <entry>org.apache.eve.client</entry>
+ <entry>Maintains and tracks client sessions.</entry>
+ </row>
+ <row>
+ <entry>Decoder</entry>
+ <entry>org.apache.eve.decoder</entry>
+ <entry>Demarshals ASN.1 BER LDAPv3 messages</entry>
+ </row>
+ <row>
+ <entry>Encoder</entry>
+ <entry>org.apache.eve.encoder</entry>
+ <entry>Marshals ASN.1 BER LDAPv3 messages</entry>
+ </row>
+ <row>
+ <entry>EventManager</entry>
+ <entry>org.apache.eve.event.protocol</entry>
+ <entry>
+ Central point for firing and recieving protocol
+ events - not related to stage events.
+ </entry>
+ </row>
+ <row>
+ <entry>InputManager</entry>
+ <entry>org.apache.eve.input</entry>
+ <entry>
+ Detects input on client channels to invoke the
+ decoder.
+ </entry>
+ </row>
+ <row>
+ <entry>Encoder</entry>
+ <entry>org.apache.eve.encoder</entry>
+ <entry>Marshals ASN.1 BER LDAPv3 messages</entry>
+ </row>
+ <row>
+ <entry>JndiProvider</entry>
+ <entry>org.apache.eve.jndi</entry>
+ <entry>
+ Factory for internal serverside JNDI LdapContexts
+ </entry>
+ </row>
+ <row>
+ <entry>ServerListener</entry>
+ <entry>org.apache.eve.listener</entry>
+ <entry>
+ Detects initial connections between the client and
+ the server.
+ </entry>
+ </row>
+ <row>
+ <entry>OutputManager</entry>
+ <entry>org.apache.eve.output</entry>
+ <entry>
+ Handles response PDU buffer streaming to the client.
+ </entry>
+ </row>
+ <row>
+ <entry>ProtocolEngine</entry>
+ <entry>org.apache.eve.protocol</entry>
+ <entry>
+ The heart of the server which processes protocol
+ requests to generate the protocol responses if
+ required.
+ </entry>
+ </row>
+ <row>
+ <entry>SchemaManager</entry>
+ <entry>org.apache.eve.schema</entry>
+ <entry>
+ Maintains and stores schema related information
+ as specified in the config.xml and the various
+ schema files associated with subschema authoritative
+ areas.
+ </entry>
+ </row>
+ <row>
+ <entry>AuthenticationManager</entry>
+ <entry>org.apache.eve.security.auth</entry>
+ <entry>
+ Manages simple authentication on LDAP bind
+ operations both for admin and non-admin users.
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </section>
+
+ <section>
+ <title>Staged, Executable and Simple Modules</title>
+
+ <para>
+ As we mentioned before, not all modules are created equal. Some
+ modules participate in the SEDA aspect of the server. These modules
+ are stages and must in addition to the Module interface implement
+ the Stage interface or extend a base class in the org.apache.eve.seda
+ package.
+ </para>
+
+ <para>
+ Without replicating Matt Welsh's paper on SEDA we'll consisely
+ define a stage as an event queue, a driver thread and a worker
+ thread pool. Stages recieve events which are popped off their
+ event queues and handed off to a worker thread for processing.
+ Events this way are processed in parallel and asynchronously. In
+ SEDA architectures, stages compose event processing pipelines that
+ often out perform their strictly threaded or strictly event driven
+ counterparts.
+ </para>
+
+ <para>
+ Stages in LDAPd are modeled exactly as defined above. They have an
+ event queue, a driver thread and a worker thread pool. Within the
+ LDAPd server the following core service interfaces are presently
+ implemented as stages composing the request processing pipeline:
+ </para>
+
+ <itemizedlist>
+ <listitem><para>ClientManager</para></listitem>
+ <listitem><para>OutputManager</para></listitem>
+ <listitem><para>Encoder</para></listitem>
+ <listitem><para>Decoder</para></listitem>
+ <listitem><para>ProtocolEngine</para></listitem>
+ </itemizedlist>
+
+ <para>
+ These service interfaces may not remain stages for long. Presently
+ the new IO (java.nio) functionality for nonblocking IO has not been
+ implemented. Once implemented stages may split or fuse together.
+ Some modules may remain but may no longer become stages. This is
+ dependent on how the architecture progresses. What is certain is
+ that stages will be present as the components of the mature server.
+ </para>
+
+ <para>
+ Simple modules, that are not stages also exist. The following
+ service interfaces are implemented as simple modules without the use
+ of any threads other than the thread of the caller to do work:
+ </para>
+
+ <itemizedlist>
+ <listitem><para>AtomicBackend</para></listitem>
+ <listitem><para>UnifiedBackend</para></listitem>
+ <listitem><para>EventManager</para></listitem>
+ <listitem><para>JndiProvider</para></listitem>
+ <listitem><para>SchemaManager</para></listitem>
+ <listitem><para>AuthenticationManager</para></listitem>
+ </itemizedlist>
+
+ <para>
+ Some service interfaces are not implemented as stages, or as simple
+ modules. These implementations use one or more threads to perform
+ some work outside of the thread of any caller. There are two such
+ service interfaces. First the InputManager, which detects IO on
+ client connections uses a pool of threads to listen for client
+ input stream activity. This is a temporary work around until the
+ module is implemented using selectable channels within the new IO
+ packages of the JDK 1.4+ platforms. Once channels and channel
+ selection is used to implement nonblocking IO, one single thread
+ can be used by this module to detect IO on any number of clients
+ concurrently. This is where and when the true power of SEDA will
+ reviel itself, until then we use this classic implementation.
+ </para>
+ <para>
+ The other service interface which is implemented neither as a stage
+ nor a simple module, is the ServerListener module. Currently the
+ server listener uses a single thread to listen to a single port for
+ incomming connections. Presently it cannot listen to more than one
+ port. It can be extended to listen to more ports by either using
+ non-blocking selectors on multiple server socket's bound to more
+ than one port, or it can use one pooled thread per server socket.
+ Nevertheless both these service interface implementations will
+ change, without changing the interface itself, to reduce the number
+ of threads used while increasing concurrency. These modules may also
+ fuse together using a single channel selector for both client accept
+ and input IO events.
+ </para>
+ </section>
+
+ <section>
+ <title>Service Interfaces and Modules</title>
+
+ <para>
+ Every core service interface defined is implemented as a server
+ module whether it be as a simple module, a staged module or other.
+ Each interface has a single implementation instance at runtime with
+ the exception of AtomicBackends. Several AtomicBackend
+ implementations may exist for various entry backing stores.
+ Currently, there are three different AtomicBackend types: the
+ modjdbm, modjdbc and the BerkeleyDB backend. Multiple backend
+ instances of the same type or of different types can coexist in the
+ same server process instance. Each AtomicBackend instance is only
+ required to have a unique suffix DN to differentiate itself from
+ other backends. One or more AtomicBackend instances hang off of the
+ UnifiedBackend service which is implemented by the NexusModule.
+ Below we list the various service interfaces and their corresponding
+ Module implementations excluding the AtomicBackend implementations:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>NexusModule implements UnifiedBackend</para>
+ </listitem>
+ <listitem>
+ <para>ClientModule implements ClientManager</para>
+ </listitem>
+ <listitem>
+ <para>DecoderModule implements Decoder</para>
+ </listitem>
+ <listitem>
+ <para>EncoderModule implements Encoder</para>
+ </listitem>
+ <listitem>
+ <para>EventModule implements EventManager</para>
+ </listitem>
+ <listitem>
+ <para>InputModule implements InputManager</para>
+ </listitem>
+ <listitem>
+ <para>OutputModule implements OutputManager</para>
+ </listitem>
+ <listitem>
+ <para>JndiProviderModule implements JndiProvider</para>
+ </listitem>
+ <listitem>
+ <para>ListenerModule implements ServerListener</para>
+ </listitem>
+ <listitem>
+ <para>ProtocolModule implements ProtocolEngine</para>
+ </listitem>
+ <listitem>
+ <para>SchemaModule implements SchemaManager</para>
+ </listitem>
+ <listitem>
+ <para>AuthenticationModule implements AuthenticationManager
+ </para>
+ </listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Request Processing</title>
+
+ <para>
+ Without using a highly detailed sequence diagram we shall represent
+ at a very high level the flow of SEDA based events within the system
+ while processing requests that have a single response.
+ <ulink url="images/ReqRespStageFlow.gif">Figure I</ulink>
+ is a very high
+ level stage to stage processing sequence for requests that have a
+ single response. LDAPv3 abandon and unbind requests have no
+ responses and LDAPv3 search requests may have one or more responses
+ so these requests are not entirely represented in this diagram.
+ Keep in mind that this sequence diagram trivializes the staged
+ processing by only showing the stage modules and the events they
+ generate within the pipline. Other modules that are used indirectly
+ while servicing these requests are not shown. More detail
+ concerning module interactions downstream of the ProtocolEngine are
+ provided in the protocol engine's implementation documentation where
+ each request processor implementation is outlined.
+ </para>
+
+ <para>
+ Briefly, Abandon and Unbind requests never produce a response and
+ Search requests have the potential of generating more than one
+ response. Reponseless requests simply stop processing after the
+ respective request processor completes processing within the
+ ProtocolModule. The Search request is more complex requiring
+ synchronized delivery of messages in a specific order. Special
+ methods are used to bypass staged event handling both in the
+ EncoderModule and in the OutputModule when search requests with more
+ than one response are processed. Serial delivery of entry responses
+ in a search requires special synchronous pathways through the
+ Encoder and Output modules. The last search done reponse, however
+ goes through the standard staged event handling mechanism. Again,
+ Search, Abandon and Unbind LDAPv3 request processing is discussed
+ in more detail within the low level implementation document for the
+ ProtocolModule.
+ </para>
+
+ <section>
+ <title>Input Detection Stage</title>
+ <para>
+ In the solid state, when all modules have started up, and after
+ a client has established a connection, an input handler assigned
+ to every client connection, blocks waiting for IO activity on
+ the input stream of the client socket. Once incomming data is
+ detected an InputEvent is generated and enqueued on the event
+ queue of the DecoderModule.
+ </para>
+ </section>
+ <section>
+ <title>
+ Protocol Data Unit (PDU) Decoding Stage (PDU Demarshaling)
+ </title>
+ <para>
+ Once the InputEvent is dequeued and processed a decoding occurs
+ while reading the input stream to build a LDAP request message
+ envelope. This stage demarshals the incoming PDU on the client
+ input stream using Binary Encoding Rules (BER). Once the
+ demarshaling is complete a RequestEvent is assembled with the
+ demarshalled request PDU and enqueued onto the ProtocolModule
+ stage for handling and response generation.
+ </para>
+ </section>
+ <section>
+ <title>Request Protocol Handling Stage</title>
+ <para>
+ Once the RequestEvent is dequeued by the ProtocolModule's driver
+ thread a protocol request processor is created to process the
+ request PDU. A stage worker pool thread is used to drive the
+ processing. Depending on the nature of the protocol request
+ various modules downstream from protocol engine may be directly
+ or indirectly called upon to complete the request. Most of the
+ time the NexusModule is called which routes requests to the
+ appropriate target backend based on the backend suffix. Some
+ protocol requests are special in that they do not return a
+ response or potentially return more than one response. Such
+ protocol request types are refered to specifically in the
+ protocol engine documentation. For the majority of request
+ types the processors generate a response message envelope to
+ be delivered back to the client on the socket output stream.
+ The protocol engine can differentiate between those request
+ types that generate a response and those that do not. After,
+ and if, a response is generated, it is packaged within a newly
+ created ResponseEvent. This event is enqueued onto the Encoder
+ stage's event queue.
+ </para>
+ </section>
+ <section>
+ <title>Response Encoding Stage (PDU Marshaling)</title>
+ <para>
+ Once the ResponseEvent is popped off of the event queue by the
+ driver thread of the EncoderModule, the packaged response
+ message envelope (LDAPMessage instance) is accessed. The object
+ is marshalled into a BER encoded buffer stream. A input stream
+ to this buffer is created and packaged within a OutputEvent
+ which is then enqueued on the event queue of the OutputModule
+ stage.
+ </para>
+ </section>
+ <section>
+ <title>Output Handling Stage</title>
+ <para>
+ Once the OutputEvent is popped off of the event queue by the
+ driver thread of the OutputModule, the encoded response PDU can
+ be pumped from the buffer into the OutputStream of the client.
+ Synchronized access to the OutputStream of the client is
+ acquired from the ClientModule using the ClientKey packaged in
+ the OutputEvent. A worker thread form the stage's worker thread
+ pool is assigned to pump the bytes stored in the BER encoded
+ buffer accessed via an InputStream into the OutputStream of
+ the client. This is not an optimal implementation but it works
+ for now allowing for full system integration testing.
+ Optimization efforts specifically targeting the JDK1.4 platform
+ (using non-blocking selectors and fast direct memory buffers)
+ will be underway within the first beta releases.
+ </para>
+ </section>
+ </section>
+
+ <section>
+ <title>Module Interdependence</title>
+
+ <para>
+ Modules within the server indirectly depend on one another since
+ they must call each other's service interface methods to process
+ client requests. Modules depend on service interfaces (ROLE's), not
+ on module's implementing those interfaces. This keeps the modules
+ decoupled and is a motif brought about through the use of Avalon.
+ Cyclic dependencies can however create a chicken and egg problem for
+ the server kernel (container) used to fire up the server's modules.
+ </para>
+
+ <para>
+ The LDAPd server avoids these cyclic dependencies by designating the
+ ClientModule as a master module and those that depend on it in a
+ cycle as ClientManagerSlaves. Many modules need to access client
+ session information managed by the ClientModule. The ClientModule
+ however passes on requests to the InputModule, which later passes
+ on requests to the ProtocolModule and so on until the OutputModule.
+ If any of these modules downstream of the ClientModule need to
+ access the client's session or request its termination they need to
+ make calls to the ClientModule's service interface. This imposes a
+ cyclic dependency when standard container mechanisms are used
+ to get handles on the services an interface modules depend upon. In
+ Avalon Framework, the Serviceable interface (required by all LDAPd
+ Modules) has the service method, which is the standard mechanism for
+ getting a handle on another service. When containers detect cycles
+ by monitoring the service lookups made by a Serviceable component,
+ they complain and reject initialization. Our little workaround for
+ these unavoidable cyclic dependencies is to, in some respects,
+ violate, yet formalize a registration mechanism outside of the
+ Serviceable paradigm, thereby bypassing cycle detection in some
+ pathological cases.
+ </para>
+
+ <para>
+ Upon recommendations from the Avalon team we constructed a special
+ ClientManagerSlave interface. This interface has a single method
+ which is used to register the ClientModule (a.k.a. the
+ ClientManager). By passing the handle to the ClientManager using
+ ClientModule initiated registration, modules dependent on the
+ ClientManager service need not raise cyclic dependency errors.
+ Regardless cyclic references exists but because the Serviceable
+ interface is not used to grab the handle containers don't choke.
+ This is why the InputManager, OutputManager and the ProtocolEngine
+ interfaces extend the ClientManagerSlave interface. On
+ initialization the ClientManager registers itself with the
+ ClientManagerSlaves so they need not lookup the ClientManager within
+ the service lifecycle method.
+ </para>
+
+ <para>
+ <ulink url="images/ModuleDependencies.gif">Figure II</ulink>
+ is a component
+ diagram which depicts the service interfaces and the modules that
+ implement them. The components are modules that have a solid
+ supporting link to a circular service interface node. Note that
+ the modules are service interface implementations and they have
+ directed dotted line dependencies on the service interfaces
+ supported by other modules. Modules never directly depend on other
+ modules, nor should they ever!
+ </para>
+ </section>
+
+ <section>
+ <title>Conclusion</title>
+ <para>
+ Our goals in this article were to introduce the fundimental modular
+ architecture of the server. We want readers to be able to
+ comprehend how server modules are defined according to the Avalon
+ Framework APIs. Readers should therefore understand what a module
+ is as a Avalon Component and which service interface is supported
+ by each critical server module. We would also like readers to step
+ away with a rough understanding of the SEDA stages within the server
+ and to be able to differentiate between simple modules, stages and
+ those that fall under neither category. Ultimately users should
+ possess an understanding of module dependencies and their
+ interactions within the processing pipeline for LDAP requests with
+ the subsequent transmission of a response.
+ </para>
+ </section>
+
+</article>
Added: incubator/directory/eve/branches/start/src/docbook/design/triggers-and-procedures.xml
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/docbook/design/triggers-and-procedures.xml Thu Jun 24 00:06:35 2004
@@ -0,0 +1,121 @@
+<!DOCTYPE article PUBLIC "-//OASIS//DTD Simplified DocBook XML V4.1.2.5//EN"
+ "http://www.oasis-open.org/docbook/xml/simple/4.1.2.5/sdocbook.dtd">
+
+
+<article>
+<title>Triggers and Stored Procedures</title>
+
+<para>
+ All of us that have had serious experience using a traditional RDBMS are more
+ than familiar with the use of triggers and stored procedures. Triggers and
+ stored procedures provide the basic framework for a rich application development
+ platform. We agree with most architects when we reject the idea of using the
+ integration teir for the development of whole applications. However it is a
+ place where peices specific to the integration teir can be developed as
+ components in the overall application. Sometimes there is no way to avoid
+ using these component even though they can be ignored for the majority of
+ applications. In this way, triggers and stored procedures are a nice feature
+ to have in any data management system if the need requires them.
+</para>
+
+<para>
+ Triggers and stored procedures have played a major role in the database world.
+ Why not enable the facility within the world of the directory? Directories unlike
+ databases have until recently been a nacent and uncommon technology. In total
+ LDAP has existed for less than two decades. The demand for LDAP is just now
+ catching on as directories become a staple component in the architect's palette.
+ The idea of architecting for the constant shared data in a system as well as the
+ ever changing data is finally manifesting itself. As applications using directory
+ services increase so do the potential for circumstances requiring the use of
+ triggers. Just recently the some effort have begun to incorporate triggers into
+ the LDAP specification as an extention. The LTAP (Lightweigth Trigger Access
+ Process) http://ltap.bell-labs.com/ is one step in that direction but it implements
+ LDAP triggers using a gateway process blanketed over an existing directory. Ldapd
+ incorporates such functionality directly into the server.
+</para>
+
+<para>
+ This chapter explores an experimental trigger and stored procedure subsystem
+ within the ldapd server. The LDAP tigger and stored procedure counterparts
+ are not all that different from those in the world of databases. The idea is
+ essentially the same. A trigger defines the conditions required to fire.
+ Firing a trigger invokes a stored procedure or an embedded procedure specified
+ as the body of the trigger. Hence like a business rule a trigger has a LHS
+ specifying the conditions for firing it and a RHS specifying the actions to take
+ when fired. Our goals are to describe how these subsystems have been designed,
+ and implemented in ldapd. Consequently we will show how triggers can be specified,
+ and enabled within a directory information tree served by ldapd.
+</para>
+
+<section>
+ <title>
+ UseCases and Conventions
+ </title>
+
+ <para>
+ some text here.
+ </para>
+
+ <para>
+ SOME NOTES ON TRIGGERS
+
+ Triggers are going to need some sort of trigger specification. This spec
+ must describe whether trigger itself is relicated and whether or not the
+ resultant changes induced by the trigger are replicated. Conversely we
+ may descide to put these parameters into a stored procedure spec instead
+ that way a timer driven firing of a stored proc may suppress replication.
+
+ If a trigger itself is replicated then it cannot replicate the effects of
+ the opperation because then the operations would be executed twice on the
+ replicas. Once by the operation of the replicated trigger, and again by
+ the replicated events fired as the result of the trigger firing on the
+ master. So a trigger is either replicated and does not replicate resultant
+ change driven events or is not replicated and does replicate the resultant
+ events caused by the stored procedures it executes.
+
+ Sometime there are scenarios when one scheme will be better than the other.
+ For example an involved CPU intensive procedure that updates only one entry
+ like a time triggered summary job may be better off kept on the master without
+ replicating the trigger and only replicating the events triggered by the
+ execution of its stored procedure. This way the expensive operations is
+ run once and its results are replicated rather than running the operation
+ on every replica. Conversely if the trigger's execution results in a large
+ number of changes then it may be best to replicate the trigger and not its
+ results because the amount of network communication required may be
+ detrimental.
+ </para>
+ <programlisting>
+ trigger : CREATE TRIGGER NAME
+ OWNED BY dn [ ON USERS dn+ ] [ AS dn ] when ENTITY matches DO procedure ;
+ when : WHEN ( BEFORE | AFTER | FAILED )
+ ( ADD | DELETE | MODIFY | READ | BIND | UNBIND )+ ;
+ matches : MATCHES dn '?' [ scope ] '?' [ filter ] '?' [ FIELDS attribName+ ] ;
+ procedure : NAME | LANG ( JAVA | JYTHON ) '{' code '}' ;
+
+
+ attributetype ( UNDEFINED_OID
+ NAME 'op'
+ DESC 'An LDAP Operation'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+ objectclass ( UNDEFINED_OID
+ NAME 'trigger'
+ DESC 'LDAP trigger'
+ SUP top
+ MAY ( run-as $ )
+ MUST ( uid $ owner $ op $ when $ match $ procedure )
+ )
+
+ LDAPv2 (RFC 1777) and LDAPv3 (RFCs 2251 through 2256) compliant, including support for
+ extensible schema, referrals, paged results, and change log extensions
+
+ Dynamically computed virtual attributes for integration with other information sources
+ </programlisting>
+ <para>
+
+
+ </para>
+</section>
+
+</article>
Added: incubator/directory/eve/branches/start/src/images/AddRequestProcessorProcess.gif
==============================================================================
Binary file. No diff available.
Added: incubator/directory/eve/branches/start/src/images/AdminSchemaContext.gif
==============================================================================
Binary file. No diff available.
Added: incubator/directory/eve/branches/start/src/images/BackendInterfaces.gif
==============================================================================
Binary file. No diff available.
Added: incubator/directory/eve/branches/start/src/images/BindRequestProcessorProcess.gif
==============================================================================
Binary file. No diff available.
Added: incubator/directory/eve/branches/start/src/images/CRUDLifecycle.gif
==============================================================================
Binary file. No diff available.
Added: incubator/directory/eve/branches/start/src/images/CompareRequestProcessorProcess.gif
==============================================================================
Binary file. No diff available.
Added: incubator/directory/eve/branches/start/src/images/DelRequestProcessorProcess.gif
==============================================================================
Binary file. No diff available.
Added: incubator/directory/eve/branches/start/src/images/ExtendedRequestProcessorProcess.gif
==============================================================================
Binary file. No diff available.
Added: incubator/directory/eve/branches/start/src/images/InputEventHandlerHandleEvent.gif
==============================================================================
Binary file. No diff available.
Added: incubator/directory/eve/branches/start/src/images/InputModuleRegister.gif
==============================================================================
Binary file. No diff available.
Added: incubator/directory/eve/branches/start/src/images/ListenerModuleRun.gif
==============================================================================
Binary file. No diff available.
Added: incubator/directory/eve/branches/start/src/images/ModifyDNRequestProcessorProcess.gif
==============================================================================
Binary file. No diff available.
Added: incubator/directory/eve/branches/start/src/images/ModifyRequestProcessorProcess.gif
==============================================================================
Binary file. No diff available.
Added: incubator/directory/eve/branches/start/src/images/ModuleDependencies.gif
==============================================================================
Binary file. No diff available.
Added: incubator/directory/eve/branches/start/src/images/OutputEventHandlerHandleEvent.gif
==============================================================================
Binary file. No diff available.
Added: incubator/directory/eve/branches/start/src/images/OutputModuleWrite.gif
==============================================================================
Binary file. No diff available.
Added: incubator/directory/eve/branches/start/src/images/ReqRespStageFlow.gif
==============================================================================
Binary file. No diff available.
Added: incubator/directory/eve/branches/start/src/images/RequestEventHandlerHandleEvent.gif
==============================================================================
Binary file. No diff available.
Added: incubator/directory/eve/branches/start/src/images/ResponseEventHandlerHandleEvent.gif
==============================================================================
Binary file. No diff available.
Added: incubator/directory/eve/branches/start/src/images/SearchRequestProcessorProcess.gif
==============================================================================
Binary file. No diff available.
Added: incubator/directory/eve/branches/start/src/images/UnBindRequestProcessorProcess.gif
==============================================================================
Binary file. No diff available.
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/AbstractModule.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/AbstractModule.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,123 @@
+/*
+ * $Id: AbstractModule.java,v 1.2 2003/03/13 18:26:29 akarasulu Exp $
+ * $Prologue$
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve ;
+
+import org.apache.avalon.framework.logger.Logger ;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.context.Context;
+import org.apache.avalon.framework.context.ContextException;
+
+
+/**
+ * Abstract module class provided for convenience. Provides start, stop and
+ * logger methods out of the box. Subclasses that override start and stop must
+ * call start() and stop() super class methods after performing their required
+ * opertations in the respective override.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.2 $
+ */
+public abstract class AbstractModule
+ implements Module
+{
+ /** The logger used by this LogEnabled module. */
+ private Logger m_logger = null ;
+ /** Member used to track whether or not this module has been started. */
+ private boolean m_hasStarted = false ;
+
+
+
+ public void service(ServiceManager a_manager)
+ throws ServiceException
+ {
+ }
+
+
+ public void initialize()
+ throws Exception
+ {
+ }
+
+
+ /**
+ * Starts this module. All subclasses much call this super method after
+ * performing their own start tasks.
+ *
+ * @throws Exception of any kind subclasses of which would depend on the
+ * nature of derived concrete modules.
+ */
+ public void start()
+ throws Exception
+ {
+ m_hasStarted = true ;
+ }
+
+
+ /**
+ * Stops this module. All subclasses much call this super method after
+ * performing their own stop tasks.
+ *
+ * @throws Exception of any kind subclasses of which would depend on the
+ * nature of derived concrete modules.
+ */
+ public void stop()
+ throws Exception
+ {
+ m_hasStarted = false ;
+ }
+
+
+ /**
+ * Checks to see if this module has started.
+ *
+ * @return true if it has started, false otherwise.
+ */
+ public final boolean hasStarted()
+ {
+ return m_hasStarted ;
+ }
+
+
+ /**
+ * Gets the Logger used by this module to log messages.
+ *
+ * @return this modules Logger.
+ */
+ public final Logger getLogger()
+ {
+ return m_logger ;
+ }
+
+
+ /**
+ * LogEnabled interface implementation which sets this Modules or LogEnabled
+ * class' Logger.
+ *
+ * @param a_logger used by this LogEnabled module.
+ */
+ public void enableLogging(Logger a_logger)
+ {
+ m_logger = a_logger ;
+ }
+
+
+ public void contextualize(Context a_context)
+ throws ContextException
+ {
+ if(getLogger().isDebugEnabled()) {
+ getLogger().debug(this.getImplementationName() +
+ " executing contextualize phase") ;
+ }
+ }
+}
+
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/Kernel.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/Kernel.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,63 @@
+/*
+ * $Id: Kernel.java,v 1.4 2003/08/22 21:15:54 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve ;
+
+
+import org.apache.avalon.framework.logger.Logger ;
+import org.apache.avalon.framework.service.ServiceManager ;
+
+
+/**
+ * Some very primitive functionality to a kernel used to fire up the server or
+ * just parts of it.
+ */
+public interface Kernel
+{
+ /**
+ * Gets path to the root directory where the sar has been unraveled.
+ */
+ String getRoot() ;
+
+ /**
+ * Sets the root directory where the sar has been unraveled. Must be set
+ * before bootstraping.
+ */
+ void setRoot( String a_rootDirPath ) ;
+
+ /**
+ * Starts up the kernel starting a single module and all modules it depends
+ * on. Using this configuration backend subsystems alone can be started
+ * without firing up the entire server.
+ */
+ void bootStrap( String a_module ) throws Exception ;
+
+ /**
+ * Starts up the entire server with all the modules.
+ */
+ void bootStrap() throws Exception ;
+
+ void shutdown() ;
+
+ /**
+ * Gets the service manager used by components to resolve dependent
+ * services exposed by server plugins.
+ */
+ ServiceManager getServiceManager() ;
+
+ /**
+ * Gets the system logger for this Kernel
+ */
+ Logger getLogger() ;
+
+ /**
+ * Gets the component logger for a module in this Kernel.
+ */
+ Logger getLogger( String a_module ) ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/Module.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/Module.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,81 @@
+/*
+ * $Id: Module.java,v 1.4 2003/08/22 21:15:54 akarasulu Exp $
+ * $Prologue$
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve ;
+
+import org.apache.avalon.framework.activity.Startable ;
+import org.apache.avalon.framework.thread.ThreadSafe ;
+import org.apache.avalon.framework.logger.LogEnabled ;
+import org.apache.avalon.framework.logger.Logger ;
+import org.apache.avalon.framework.configuration.Configurable ;
+import org.apache.avalon.framework.service.Serviceable ;
+import org.apache.avalon.framework.activity.Initializable ;
+import org.apache.avalon.framework.context.Contextualizable ;
+
+
+/**
+ * Modules are pluggable black box components that can be started and stopped
+ * and are responsible for their own error handling and logging. Some types of
+ * modules within ldapd are backend modules and replication modules.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.4 $
+ */
+public interface Module
+ extends
+ Startable,
+ ThreadSafe,
+ LogEnabled,
+ Serviceable,
+ Configurable,
+ Contextualizable,
+ Initializable
+{
+ /**
+ * Gets the service interface name of this module.
+ *
+ * @return the role of this module's implemented service.
+ */
+ String getImplementationRole() ;
+
+ /**
+ * Gets the name of the implementation. For example the name of the
+ * Berkeley DB Backend module is "Berkeley DB Backend".
+ *
+ * @return String representing the module implementation type name.
+ */
+ String getImplementationName() ;
+
+ /**
+ * Gets the name of the implementation class. For example the name of the
+ * Berkeley DB Backend implementation class is <code>
+ * "ldapdd.backend.berkeley.BackendBDb" </code>.
+ *
+ * @return String representing the module implementation's class name.
+ */
+ String getImplementationClassName() ;
+
+
+ /**
+ * Checks to see if this module has already started.
+ *
+ * @return true if the module started, false otherwise.
+ */
+ boolean hasStarted() ;
+
+ /**
+ * Gets the logger used by this module to log messages.
+ *
+ * @return the logger used by this module.
+ */
+ Logger getLogger() ;
+}
+
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/AtomicBackend.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/AtomicBackend.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,40 @@
+/*
+ * $Id: AtomicBackend.java,v 1.5 2003/08/22 21:15:54 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend ;
+
+
+import javax.naming.Name ;
+import org.apache.eve.schema.Schema ;
+
+
+/**
+ * Atomic backends represent a concrete configurable Directory Information Base
+ *(DIB). They are not composed of other Backends.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.5 $
+ */
+public interface AtomicBackend
+ extends Backend, BackendConfig
+{
+ /**
+ * Role of this service interface as mandated by the avalon framework.
+ */
+ public static final String ROLE = AtomicBackend.class.getName() ;
+
+ /**
+ * Gets the normalized DN of the suffix managed by this AtomicBackend.
+ *
+ * @return Name representing the normalized root suffix for this
+ * AtomicBackend.
+ */
+ Name getSuffix() ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/AttributeAdapter.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/AttributeAdapter.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,198 @@
+/*
+ * $Id: AttributeAdapter.java,v 1.3 2003/04/09 15:51:25 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend ;
+
+
+import java.util.Vector ;
+import java.util.Iterator ;
+import java.util.ArrayList ;
+import java.util.Collection ;
+
+import javax.naming.NamingException ;
+import org.apache.ldap.common.NotImplementedException ;
+import javax.naming.NamingEnumeration ;
+import javax.naming.directory.Attribute ;
+import javax.naming.directory.DirContext ;
+
+
+/**
+ * Attribute adapter which is a simple wrapper around a Collection.
+ */
+public class AttributeAdapter
+ implements Attribute
+{
+ Collection m_collection ;
+ String m_id ;
+
+
+ public AttributeAdapter(Collection a_collection, String a_id) {
+ m_id = a_id ;
+ m_collection = a_collection ;
+ }
+
+
+ public NamingEnumeration getAll() throws NamingException
+ {
+ final Iterator l_list = m_collection.iterator() ;
+ return new NamingEnumeration() {
+ public boolean hasMore() { return l_list.hasNext() ; }
+ public boolean hasMoreElements() { return l_list.hasNext() ; }
+ public Object nextElement() { return l_list.next() ; }
+ public Object next() { return l_list.next() ; }
+ public void close() {}
+ } ;
+ }
+
+
+ public Object get() throws NamingException
+ {
+ if(m_collection instanceof ArrayList) {
+ ArrayList l_al = (ArrayList) m_collection ;
+ if(l_al.size() > 0) {
+ return l_al.get(0) ;
+ } else {
+ return null ;
+ }
+ }
+
+ throw new NotImplementedException() ;
+ }
+
+
+ public int size()
+ {
+ return m_collection.size() ;
+ }
+
+
+ public String getID()
+ {
+ return m_id ;
+ }
+
+
+ public boolean contains(Object attrVal)
+ {
+ return m_collection.contains(attrVal) ;
+ }
+
+
+ public boolean add(Object attrVal)
+ {
+ if(m_collection.contains(attrVal)) {
+ return false ;
+ } else {
+ m_collection.add(attrVal) ;
+ return true ;
+ }
+ }
+
+
+ public boolean remove(Object attrval)
+ {
+ return m_collection.remove(attrval) ;
+ }
+
+
+ public void clear()
+ {
+ m_collection.clear() ;
+ }
+
+
+ public DirContext getAttributeSyntaxDefinition() throws NamingException
+ {
+ throw new UnsupportedOperationException(
+ "AttributeAdapter does not support schema info right now.") ;
+ }
+
+
+ public DirContext getAttributeDefinition() throws NamingException
+ {
+ throw new UnsupportedOperationException(
+ "AttributeAdapter does not support schema info right now.") ;
+ }
+
+
+ public Object clone() {
+ throw new UnsupportedOperationException(
+ "AttributeAdapter for event delivery does not support clone().") ;
+ }
+
+ //----------- Methods to support ordered multivalued attributes
+
+ public boolean isOrdered()
+ {
+ if(m_collection instanceof Vector ||
+ m_collection instanceof ArrayList) {
+ return true ;
+ }
+
+ return false ;
+ }
+
+
+ public Object get(int ix) throws NamingException
+ {
+ if(m_collection instanceof ArrayList) {
+ return ((ArrayList) m_collection).get(ix) ;
+ } else if(m_collection instanceof Vector) {
+ return ((Vector) m_collection).get(ix) ;
+ }
+
+ throw new UnsupportedOperationException(
+ "Collection of " + m_collection.getClass().getName()
+ + "does not support ordered access to attribute values") ;
+ }
+
+
+ public Object remove(int ix)
+ {
+ if(m_collection instanceof ArrayList) {
+ return ((ArrayList) m_collection).remove(ix) ;
+ } else if(m_collection instanceof Vector) {
+ return ((Vector) m_collection).remove(ix) ;
+ }
+
+ throw new UnsupportedOperationException(
+ "Collection of " + m_collection.getClass().getName()
+ + "does not support ordered removal of attribute values") ;
+ }
+
+
+ public void add(int ix, Object attrVal)
+ {
+ if(m_collection instanceof ArrayList) {
+ ((ArrayList) m_collection).add(ix, attrVal) ;
+ return ;
+ } else if(m_collection instanceof Vector) {
+ ((Vector) m_collection).add(ix, attrVal) ;
+ return ;
+ }
+
+ throw new UnsupportedOperationException(
+ "Collection of " + m_collection.getClass().getName()
+ + "does not support ordered addition to attribute values") ;
+ }
+
+
+ public Object set(int ix, Object attrVal)
+ {
+ if(m_collection instanceof ArrayList) {
+ return ((ArrayList) m_collection).set(ix, attrVal) ;
+ } else if(m_collection instanceof Vector) {
+ return ((Vector) m_collection).set(ix, attrVal) ;
+ }
+
+ throw new UnsupportedOperationException(
+ "Collection of " + m_collection.getClass().getName()
+ + "does not support ordered alteration of attribute values") ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/AttributesAdapter.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/AttributesAdapter.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,236 @@
+/*
+ * $Id: AttributesAdapter.java,v 1.4 2003/04/09 15:51:25 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend ;
+
+
+import java.util.Vector ;
+import java.util.Iterator ;
+import java.util.ArrayList ;
+import java.util.Collection ;
+
+
+import javax.naming.NamingException ;
+import javax.naming.NamingEnumeration ;
+import javax.naming.directory.Attribute ;
+import javax.naming.directory.DirContext ;
+import javax.naming.directory.Attributes ;
+
+import org.apache.ldap.common.NotImplementedException ;
+
+import org.apache.avalon.framework.CascadingRuntimeException ;
+
+
+/**
+ * An Attributes interface adapter around an LdapEntry.
+ */
+public class AttributesAdapter
+ implements Attributes
+{
+ private final LdapEntry m_entry ;
+
+
+ public AttributesAdapter(LdapEntry a_entry) {
+ m_entry = a_entry ;
+ }
+
+
+ /**
+ * Determines whether the attribute set ignores the case of
+ * attribute identifiers when retrieving or adding attributes.
+ * @return true if case is ignored; false otherwise.
+ */
+ public boolean isCaseIgnored()
+ {
+ return true ;
+ }
+
+
+ /**
+ * Retrieves the number of attributes in the attribute set.
+ *
+ * @return The nonnegative number of attributes in this attribute set.
+ */
+ public int size()
+ {
+ return m_entry.attributes().size() ;
+ }
+
+ /**
+ * Retrieves the attribute with the given attribute id from the
+ * attribute set.
+ *
+ * @param attrID The non-null id of the attribute to retrieve.
+ * If this attribute set ignores the character
+ * case of its attribute ids, the case of attrID
+ * is ignored.
+ * @return The attribute identified by attrID; null if not found.
+ * @see #put
+ * @see #remove
+ */
+ public Attribute get(String attrId)
+ {
+ if(m_entry.hasAttribute(attrId)) {
+ return new AttributeAdapter(m_entry.getMultiValue(attrId), attrId) ;
+ }
+
+ return null ;
+ }
+
+
+ /**
+ * Retrieves an enumeration of the attributes in the attribute set.
+ * The effects of updates to this attribute set on this enumeration
+ * are undefined.
+ *
+ * @return A non-null enumeration of the attributes in this attribute set.
+ * Each element of the enumeration is of class <tt>Attribute</tt>.
+ * If attribute set has zero attributes, an empty enumeration
+ * is returned.
+ */
+ public NamingEnumeration getAll()
+ {
+ final Iterator l_list = m_entry.attributes().iterator() ;
+ return new NamingEnumeration() {
+ public boolean hasMore() { return l_list.hasNext() ; }
+ public boolean hasMoreElements() { return l_list.hasNext() ; }
+ public Object nextElement()
+ {
+ String l_attrId = (String) l_list.next() ;
+ Attribute l_attr = new AttributeAdapter(
+ m_entry.getMultiValue(l_attrId), l_attrId) ;
+ return l_attr ;
+ }
+ public Object next()
+ {
+ String l_attrId = (String) l_list.next() ;
+ Attribute l_attr = new AttributeAdapter(
+ m_entry.getMultiValue(l_attrId), l_attrId) ;
+ return l_attr ;
+ }
+ public void close() {}
+ } ;
+ }
+
+
+ /**
+ * Retrieves an enumeration of the ids of the attributes in the
+ * attribute set.
+ * The effects of updates to this attribute set on this enumeration
+ * are undefined.
+ *
+ * @return A non-null enumeration of the attributes' ids in
+ * this attribute set. Each element of the enumeration is
+ * of class String.
+ * If attribute set has zero attributes, an empty enumeration
+ * is returned.
+ */
+ public NamingEnumeration getIDs()
+ {
+ final Iterator l_list = m_entry.attributes().iterator() ;
+ return new NamingEnumeration() {
+ public boolean hasMore() { return l_list.hasNext() ; }
+ public boolean hasMoreElements() { return l_list.hasNext() ; }
+ public Object nextElement() { return l_list.next() ; }
+ public Object next() { return l_list.next() ; }
+ public void close() {}
+ } ;
+ }
+
+
+ /**
+ * Adds a new attribute to the attribute set.
+ *
+ * @param attrID non-null The id of the attribute to add.
+ * If the attribute set ignores the character
+ * case of its attribute ids, the case of attrID
+ * is ignored.
+ * @param val The possibly null value of the attribute to add.
+ * If null, the attribute does not have any values.
+ * @return The Attribute with attrID that was previous in this attribute set;
+ * null if no such attribute existed.
+ * @see #remove
+ */
+ public Attribute put(String attrID, Object val)
+ {
+ try {
+ m_entry.addValue(attrID, val) ;
+ } catch(NamingException e) {
+ throw new CascadingRuntimeException("Naming exception thrown", e) ;
+ }
+
+ return new AttributeAdapter(m_entry.getMultiValue(attrID), attrID) ;
+ }
+
+
+ /**
+ * Adds a new attribute to the attribute set.
+ *
+ * @param attr The non-null attribute to add.
+ * If the attribute set ignores the character
+ * case of its attribute ids, the case of
+ * attr's identifier is ignored.
+ * @return The Attribute with the same ID as attr that was previous
+ * in this attribute set;
+ * null if no such attribute existed.
+ * @see #remove
+ */
+ public Attribute put(Attribute attr)
+ {
+ try {
+ NamingEnumeration l_list = attr.getAll() ;
+ while(l_list.hasMore()) {
+ m_entry.addValue(attr.getID(), l_list.next()) ;
+ }
+
+ return new AttributeAdapter(m_entry.getMultiValue(attr.getID()),
+ attr.getID());
+ } catch(NamingException e) {
+ throw new CascadingRuntimeException("Naming exception thrown", e) ;
+ }
+ }
+
+
+ /**
+ * Removes the attribute with the attribute id 'attrID' from
+ * the attribute set. If the attribute does not exist, ignore.
+ *
+ * @param attrID The non-null id of the attribute to remove.
+ * If the attribute set ignores the character
+ * case of its attribute ids, the case of
+ * attrID is ignored.
+ * @return The Attribute with the same ID as attrID that was previous
+ * in the attribute set;
+ * null if no such attribute existed.
+ */
+ public Attribute remove(String attrId)
+ {
+ try {
+ Attribute l_attr =
+ new AttributeAdapter(m_entry.getMultiValue(attrId), attrId) ;
+ m_entry.removeValues(attrId) ;
+ return l_attr ;
+ } catch(NamingException e) {
+ throw new CascadingRuntimeException("Naming exception thrown", e) ;
+ }
+ }
+
+
+ /**
+ * Makes a copy of the attribute set.
+ * The new set contains the same attributes as the original set:
+ * the attributes are not themselves cloned.
+ *
+ * @return A non-null copy of this attribute set.
+ */
+ public Object clone() {
+ throw new UnsupportedOperationException(
+ "AttributesAdapter for event delivery does not allow clone ops.") ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/Backend.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/Backend.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,375 @@
+/*
+ * $Id: Backend.java,v 1.9 2003/03/27 16:30:37 jmachols Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend ;
+
+
+import javax.naming.Name ;
+import javax.naming.NamingException ;
+import javax.naming.directory.DirContext ;
+import javax.naming.directory.SearchControls ;
+
+import org.apache.ldap.common.filter.ExprNode ;
+import org.apache.eve.client.ClientManagerSlave ;
+
+
+/**
+ * Backend modules store entries in a manner specific to a backing store.
+ *
+ * Backends may be memory resident non persistant stores, use flat files, xml,
+ * relational databases, non relational databases, or even other surrogate LDAP
+ * directories to store entries in whatever scheme they see fit. No limitations
+ * are placed on how Backends store or manage entries.
+ *
+ * These interfaces simply define a means to get to Entry attributes in a
+ * standard way. Hence this interface establishes one of the primary contracts
+ * that the ldap server holds with a pluggable backend module. Other
+ * complementary interfaces in this package are artifacts that are required to
+ * interface with a Backend or the attribute contents of entries. Backend
+ * implementations must uphold these server-backend contracts.
+ *
+ * Related Documentation:
+ * <ul>
+ * <li><a href=backendhowto.html>HowTo Build A Backend</a></li>
+ * <li><a href=dnnormalization.html>Distinguished Name Normalization</a></li>
+ * <li><a href=contract.html>Server-Backend Contract.</a></li>
+ * <li><a href=http://afs.wu-wien.ac.at/manuals/rfc-ldap.html>
+ * Relevant LDAP RFCs</a></li></ul>
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: jmachols $
+ * @version $Revision: 1.9 $
+ */
+public interface Backend extends ClientManagerSlave
+{
+ /**
+ * Constant used to represent object level search scope which equals
+ * SearchControls.OBJECT_SCOPE.
+ */
+ int BASE_SCOPE = SearchControls.OBJECT_SCOPE ;
+ /**
+ * Constant used to represent single level search scope which equals
+ * SearchControls.ONELEVEL_SCOPE.
+ */
+ int SINGLE_SCOPE = SearchControls.ONELEVEL_SCOPE ;
+ /**
+ * Constant used to represent subtree level search scope which equals
+ * SearchControls.SUBTREE_SCOPE.
+ */
+ int SUBTREE_SCOPE = SearchControls.SUBTREE_SCOPE ;
+
+ /** Constant used to represent attribute/value addition. */
+ int ADD_ATTRIBUTE = DirContext.ADD_ATTRIBUTE ;
+ /** Constant used to represent attribute/value removal. */
+ int REMOVE_ATTRIBUTE = DirContext.REMOVE_ATTRIBUTE ;
+ /** Constant used to represent attribute/value replacement. */
+ int REPLACE_ATTRIBUTE = DirContext.REPLACE_ATTRIBUTE ;
+
+
+ ///////////////////////////
+ // Entry CRUD Operations //
+ ///////////////////////////
+
+
+ /**
+ * Creates a new Entry without adding it to the database. The entry is
+ * invalid until it is added to the instantiating backend via a create()
+ * call. The new Entry contains a single operational attribute: the DN of
+ * the Entry in the case and format specified by the user. Hence calls to
+ * the <code>getEntryDN()</code> method of the Entry shall return the DN
+ * argument to this method. Calls to the <code>getNormalizedDN()</code>
+ * method will return the normalized DN.
+ *
+ * To comply with the server backend contract the DN argument must not be
+ * tampered with by a normalizer. This method expects a_dn to be the
+ * original user provided unformatted DN.
+ *
+ * @param a_dn the user provided distinguished name of the new Entry.
+ * @return the newly instantiated Entry to be added to this Backend via the
+ * create() method.
+ * @throws javax.naming.NameNotFoundException when a component of the parent cannot be
+ * resolved because it is not bound - the parent entry of the new Entry
+ * must be bound for this factory method.
+ * @throws javax.naming.InvalidNameException when a_dn is not syntactically correct.
+ * @throws javax.naming.NameAlreadyBoundException when an Entry with a_dn already
+ * exists.
+ * @throws BackendException when a backing store error occurs.
+ */
+ LdapEntry newEntry(String a_dn)
+ throws BackendException, NamingException ;
+
+ /**
+ * Deletes (cru<b>D</b>) an entry from the Backend and all cached
+ * referrences to it. The Entry cache if any is purged of referrences to
+ * the Entry.
+ *
+ * @param an_entry Entry to be deleted
+ * @throws BackendException when removal from the backend fails due to a
+ * backing store error, or an_entry is <b>NOT</b> valid, or is not managed
+ * by this Backend.
+ * @throws javax.naming.ContextNotEmptyException when non leaf entries are attempted to
+ * be deleted.
+ */
+ void delete(LdapEntry an_entry)
+ throws BackendException, NamingException ;
+
+ /**
+ * Creates (<b>C</b>rud) an Entry in this Backend.
+ *
+ * @param an_entry to put into this Backend.
+ * @throws BackendException if anything goes drastically wrong with this
+ * Backend while attempting to perform the operation, or if an Entry with
+ * the same DN already exists within this Backend, or if the Entry is not
+ * managed by this Backend.
+ * @throws javax.naming.directory.SchemaViolationException if the attributes supplied with an
+ * entry do not satisfy objectclass schema constraints.
+ * @throws javax.naming.NameAlreadyBoundException if an Entry with a_dn already exists,
+ * this would occur if another thread creates an Entry with its DN between
+ * the call to newEntry and this method.
+ * @throws javax.naming.directory.InvalidAttributesException when all the mandatory attributes
+ * required by the objectclasses of the object are not present.
+ */
+ void create(LdapEntry an_entry)
+ throws BackendException, NamingException ;
+
+
+ /**
+ * Read (c<b>R</b>ud) an Entry from this Backend based on it's unique DN.
+ *
+ * The distinguished name argument is NOT presumed to be normalized in
+ * accordance with schema attribute syntax and attribute matching rules.
+ * The DN is also NOT presumed to be syntacticly correct or within the
+ * namespace of this directory information base. Unaware of normalization
+ * this method will attempt to normalize any DN arguements. Apriori
+ * normalization would be redundant.
+ *
+ * @param a_dn the unique distinguished name of the entry to get.
+ * @return the entry identified by a_dn or null if one by that name does
+ * not exist.
+ * @throws BackendException if anything goes drastically wrong with this
+ * Backend while attempting to perform the operation.
+ * @throws javax.naming.NameNotFoundException when a component of the name cannot be
+ * resolved because it is not bound.
+ * @throws javax.naming.InvalidNameException if a_dn is not syntactically correct.
+ */
+ LdapEntry read(Name a_dn)
+ throws BackendException, NamingException ;
+
+ /**
+ * Updates (cr<b>U</b>d) the valid Entry by presuming that it has been
+ * altered. The alterations may effect multiple attributes by adding
+ * values, removing values or changing values. The Entry must be valid
+ * for this operation to take place.
+ *
+ * @param an_entry Entry to modify
+ * @throws BackendException when the modification fails, or an_entry is not
+ * valid.
+ * @throws javax.naming.directory.SchemaViolationException if the attributes supplied with an
+ * entry do not satisfy objectclass schema constraints.
+ * @throws javax.naming.directory.InvalidAttributesException when all the mandatory attributes
+ * required by the objectclasses of the object are not present.
+ */
+ void update(LdapEntry an_entry)
+ throws BackendException, NamingException ;
+
+
+ //////////////////////////////////////
+ // Parent Child Relation Operations //
+ //////////////////////////////////////
+
+
+ /**
+ * Lists the children of an entry identified by a_dn. The returned Cursor
+ * enumerates through the children.<br>
+ * <br>
+ * The distinguished name argument is NOT presumed to be normalized in
+ * accordance with schema attribute syntax and attribute matching rules.
+ * The DN is also NOT presumed to be syntacticly correct or within the
+ * namespace of this directory information base. Unaware of normalization
+ * this method will attempt to normalize any DN arguements. Apriori
+ * normalization would be redundant.
+ *
+ * @param a_parentDN the parent entry's distinguished name.
+ * @return a cursor enumerating over the child entries of the parent.
+ * @throws BackendException if anything goes drastically wrong with this
+ * Backend while attempting to perform the operation.
+ * @throws javax.naming.NameNotFoundException when a component of the name cannot be
+ * resolved because it is not bound.
+ * @throws javax.naming.InvalidNameException if a_parentDN is not syntactically correct.
+ */
+ Cursor listChildren(Name a_parentDN)
+ throws BackendException, NamingException ;
+
+ /**
+ * Gets the parent of a child entry.
+ *
+ * The distinguished name argument is NOT presumed to be normalized in
+ * accordance with schema attribute syntax and attribute matching rules.
+ * The DN is also NOT presumed to be syntacticly correct or within the
+ * namespace of this directory information base. Unaware of normalization
+ * this method will attempt to normalize any DN arguements. Apriori
+ * normalization would be redundant.
+ *
+ * @param a_childDN the distinguished name of the child entry.
+ * @return the parent entry of an entry identified by a child DN or the
+ * child entry if the child is the suffix.
+ * @throws BackendException if anything goes drastically wrong with this
+ * Backend while attempting to perform the operation.
+ * @throws javax.naming.NameNotFoundException when a component of the name cannot be
+ * resolved because it is not bound.
+ * @throws javax.naming.InvalidNameException if a_childDN is not syntactically correct.
+ */
+ LdapEntry getParent(Name a_childDN)
+ throws BackendException, NamingException ;
+
+ /**
+ * Checks to see if an entry with a distinguished name exists within this
+ * Backend.
+ *
+ * The distinguished name argument is NOT presumed to be normalized in
+ * accordance with schema attribute syntax and attribute matching rules.
+ * The DN is also NOT presumed to be syntacticly correct or within the
+ * namespace of this directory information base. Unaware of normalization
+ * this method will attempt to normalize any DN arguements. Apriori
+ * normalization would be redundant.
+ *
+ * @param a_dn the distinguished name of the entry to check for.
+ * @return true if the entry exists within this Backend instance.
+ * @throws BackendException if anything goes drastically wrong with this
+ * Backend while attempting to perform the operation.
+ * @throws javax.naming.InvalidNameException if a_dn is not syntactically correct.
+ */
+ boolean hasEntry(Name a_dn)
+ throws BackendException, NamingException ;
+
+
+ /**
+ * Tests to see if this entry is a/the suffix Entry of this Backend.
+ * Unified composite backends will return true if the Entry is a valid
+ * suffix within the set of Backends composing it.
+ *
+ * @param an_entry the Entry to test if it is the suffix of this Backend or one of
+ * its composing Backends if this Backend is a UnifiedBackend.
+ * @return true if the Entry's DN is equivalent to the DN of this Backend,
+ * or one contained by a UnifiedBackend, otherwise false.
+ */
+ boolean isSuffix(LdapEntry an_entry)
+ throws NamingException ;
+
+ /**
+ * Checks to see if a user dn is the dn of this backend or one of its
+ * AtomicBackends if it is a UnifiedBackend.
+ *
+ * @param a_userDn the user dn to check for.
+ * @return true if a_userDn represents an admin dn, false otherwise.
+ * @throws NamingException if their is a problem with the specified user dn.
+ */
+ boolean isAdminUser(Name a_userDn)
+ throws NamingException ;
+
+ ////////////////////////
+ // Special Operations //
+ ////////////////////////
+
+ /**
+ * Searches for candidate entries on the backend starting on a base DN
+ * using a search filter with search controls.
+ *
+ * The distinguished name argument is NOT presumed to be normalized in
+ * accordance with schema attribute syntax and attribute matching rules.
+ * The DN is also NOT presumed to be syntacticly correct or within the
+ * namespace of this directory information base. Unaware of normalization
+ * this method will attempt to normalize any DN arguements. Apriori
+ * normalization would be redundant.
+ *
+ * W O R K I N P R O G R E S S
+ *
+ * @param a_filter String representation of an LDAP search filter.
+ * @param a_baseDN String representing the base of the search.
+ * @param a_scope SearchControls governing how this search is to be
+ * conducted.
+ * @throws BackendException on Backend errors or when the operation cannot
+ * proceed due to a malformed search filter, a non-existant search base, or
+ * inconsistant search controls.
+ * @throws javax.naming.InvalidNameException if a_baseDN is not syntactically correct.
+ * @throws javax.naming.NameNotFoundException when a component of a_baseDN cannot be
+ * resolved because it is not bound.
+ * @throws javax.naming.directory.InvalidSearchFilterException when the specification of a search
+ * filter is invalid. The expression of the filter may be invalid, or there
+ * may be a problem with one of the parameters passed to the filter.
+ * @throws javax.naming.directory.InvalidSearchControlsException when the specification of the
+ * SearchControls for a search operation is invalid. For example, if the
+ * scope is set to a value other than OBJECT_SCOPE, ONELEVEL_SCOPE,
+ * SUBTREE_SCOPE, this exception is thrown.
+ */
+ Cursor search(ExprNode a_filter, Name a_baseDN, int a_scope)
+ throws BackendException, NamingException ;
+
+ /**
+ * Modifies the relative distinguished name (RDN) of an entry
+ * without changing any parent child relationships. This call
+ * has the side effect of altering the distinguished name of
+ * descendent entries if they exist. The boolean argument will
+ * optionally remove the existing RDN attribute value pair
+ * replacing it with the new RDN attribute value pair. If other
+ * RDN attribute value pairs exist besides the current RDN they
+ * will be spared.
+ *
+ * @param an_entry the entry whose RDN is to be modified.
+ * @param a_newRdn the new Rdn that is to replace the current Rdn.
+ * @param a_deleteOldRdn deletes the old Rdn attribute value pair if true.
+ * @throws BackendException when the operation cannot be performed due to a
+ * backing store error.
+ * @throws NamingException when naming violations and or schema violations
+ * occur due to attempting this operation.
+ */
+ void modifyRdn(LdapEntry an_entry, Name a_newRdn, boolean a_deleteOldRdn)
+ throws BackendException, NamingException ;
+
+ /**
+ * Moves a child entry without changing the RDN under a new parent
+ * entry. This effects the parent child relationship between the
+ * parent entry and the child entry. The index for the child
+ * mapping it to the current parent is destroyed and a new index
+ * mapping it to the new parent is created. As a side effect the
+ * name of the child entry and all its descendants will reflect the
+ * move within the DIT to a new parent. The old parent prefix to
+ * the distinguished names of the child and its descendents will be
+ * replaced by the new parent DN prefix.
+ *
+ * @param a_parentEntry the parent the child is to subordinate to.
+ * @param a_childEntry the child to be moved under the parent.
+ * @throws BackendException when the operation cannot be performed due to a
+ * backing store error.
+ * @throws NamingException when naming violations and or schema violations
+ * occur due to attempting this operation.
+ */
+ void move(LdapEntry a_parentEntry, LdapEntry a_childEntry)
+ throws BackendException, NamingException ;
+
+ /**
+ * This overload combines the first two method operations into one.
+ * It changes the Rdn and the parent prefix at the same time while
+ * recursing name changes to all descendants of the child entry. It
+ * is obviously more complex than the other two operations alone and
+ * involves changes to both parent child indices and DN indices.
+ *
+ * @param a_parentEntry the parent the child is to subordinate to.
+ * @param a_childEntry the child to be moved under the parent.
+ * @param a_newRdn the new Rdn that is to replace the current Rdn.
+ * @param a_deleteOldRdn deletes the old Rdn attribute value pair if true.
+ * @throws BackendException when the operation cannot be performed due to a
+ * backing store error.
+ * @throws NamingException when naming violations and or schema violations
+ * occur due to attempting this operation.
+ */
+ void move(LdapEntry a_parentEntry, LdapEntry a_childEntry,
+ Name a_newRdn, boolean a_deleteOldRdn)
+ throws BackendException, NamingException ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/BackendConfig.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/BackendConfig.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,119 @@
+/*
+ * $Id: BackendConfig.java,v 1.4 2003/03/13 18:26:41 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend ;
+
+import java.util.Iterator ;
+import javax.naming.InvalidNameException ;
+
+import org.apache.avalon.framework.configuration.Configuration ;
+import org.apache.avalon.framework.configuration.ConfigurationException ;
+import javax.naming.Name;
+
+
+/**
+ * Interface used to manage the configuration of an AtomicBackend.
+ */
+public interface BackendConfig
+{
+ /** The default entry cache size. */
+ int DEFAULT_ENTRY_CACHESZ = 1000 ;
+
+ /**
+ * Tests to see if the backend of this configuration is operating in read
+ * only mode. If true alterations to the backend will result in
+ * ReadOnlyExceptions being thrown at runtime.
+ *
+ * @return true if the backend is in read only mode false otherwise.
+ */
+ boolean isReadOnly() ;
+
+ /**
+ * Sets the read only operational mode of a backend using this
+ * configuration.
+ *
+ * @param a_isReadOnlyMode true if backend is to be configured for read
+ * only mode false otherwise.
+ */
+ void setReadOnly(boolean a_isReadOnlyMode) ;
+
+ /**
+ * Sets the maximum size the entry cache may grow to.
+ *
+ * @param a_numMaxEntries the maximum number of entries that can be held.
+ * @throws BackendException if the configurable module has started and is
+ * not Reconfigurable.
+ */
+ void setEntryCacheSize(int a_numMaxEntries)
+ throws BackendException ;
+
+ /**
+ * Gets the absolute path to the working directory for the configurable
+ * backend.
+ *
+ * @return the absolute working directory path.
+ */
+ String getWorkingDirPath() ;
+
+ /**
+ * Sets the working directory path for implementation specific files or
+ * logs if any.
+ *
+ * @param a_dirPath the absolute path to the working directory for the
+ * configurable backend.
+ * @throws BackendException if the configurable module has started and is
+ * not Reconfigurable.
+ */
+ void setWorkingDirPath(String a_dirPath)
+ throws BackendException ;
+
+ /**
+ * Sets the password for the admin user for the configurable backend.
+ *
+ * @param an_adminDN the distinguished name of the backend admin.
+ * @throws InvalidNameException if an_adminDN does not conform to DN
+ * syntax.
+ * @throws BackendException if the configurable module has started and is
+ * not Reconfigurable.
+ * @throws InvalidNameException if an_adminDN not in correct DN syntax
+ */
+ void setAdminUserDN(Name an_adminDN)
+ throws BackendException, InvalidNameException ;
+
+ /**
+ * Gets the admin user distinguished name for the configurable backend.
+ *
+ * @return the distinguished name of the admin user.
+ */
+ Name getAdminUserDN() ;
+
+ /**
+ * Sets the password for the admin user for the configurable backend.
+ *
+ * @param an_adminPassword the distinguished name of the backend admin.
+ * @throws BackendException if the configurable module has started and is
+ * not Reconfigurable.
+ */
+ void setAdminUserPassword(String an_adminPassword)
+ throws BackendException ;
+
+ /**
+ * Gets the encrypted password of the user in base 64 encoded format.
+ *
+ * @return base64 encoded cypher.
+ */
+ String getAdminUserPassword() ;
+
+ /**
+ * Gets the maximum size the entry cache may grow to.
+ *
+ * @return the maximum number of entries that can be held.
+ */
+ int getEntryCacheSize() ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/BackendException.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/BackendException.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,44 @@
+/*
+ * $Id: BackendException.java,v 1.2 2003/03/13 18:26:42 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend ;
+
+import org.apache.avalon.framework.CascadingException ;
+
+
+/**
+ * This exception is thrown when Error encountered on backend operation.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.2 $
+ */
+public class BackendException
+ extends CascadingException
+{
+ /**
+ * Constructs an Exception with a detailed message.
+ * @param a_message The message associated with the exception.
+ */
+ public BackendException(String a_message)
+ {
+ super(a_message) ;
+ }
+
+
+ /**
+ * Constructs an Exception with a detailed message and an error.
+ * @param a_message The message associated with the exception.
+ */
+ public BackendException(String a_message, Throwable a_throwable)
+ {
+ super(a_message, a_throwable) ;
+ }
+}
+
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/BackendModule.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/BackendModule.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,482 @@
+/*
+ * $Id: BackendModule.java,v 1.10 2003/08/22 21:15:54 akarasulu Exp $
+ * $Prologue$
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend ;
+
+
+import org.apache.eve.schema.Schema ;
+import org.apache.eve.AbstractModule ;
+import org.apache.eve.client.ClientManager ;
+import org.apache.eve.schema.SchemaManager ;
+
+import java.io.File ;
+import java.util.Iterator ;
+import java.util.Collection ;
+import java.util.NoSuchElementException ;
+
+import javax.naming.Name ;
+import javax.naming.NamingException ;
+import javax.naming.InvalidNameException ;
+import javax.naming.NameNotFoundException ;
+
+import org.apache.commons.collections.LRUMap ;
+import org.apache.commons.collections.MultiMap ;
+import org.apache.commons.collections.MultiHashMap ;
+
+import org.apache.avalon.phoenix.BlockContext ;
+
+import org.apache.avalon.framework.context.Context ;
+import org.apache.avalon.framework.service.ServiceManager ;
+import org.apache.avalon.framework.service.ServiceException ;
+import org.apache.avalon.framework.context.ContextException ;
+import org.apache.avalon.framework.configuration.Configuration ;
+import org.apache.avalon.framework.configuration.ConfigurationException ;
+
+
+public abstract class BackendModule
+ extends AbstractModule
+ implements AtomicBackend
+{
+ //
+ // Configuration Variables
+ //
+
+ protected boolean m_isReadOnly = false ;
+ protected Name m_suffix = null ;
+ protected String m_wkdirPath = null ;
+ protected Name m_adminUser = null ;
+ protected String m_adminPassword = null ;
+ protected BlockContext m_context ;
+
+ protected UnifiedBackend m_nexus = null ;
+ protected ClientManager m_clientMan = null ;
+ protected SchemaManager m_schemaManager = null ;
+ protected Schema m_schema = null ;
+ protected LRUMap m_cache = new LRUMap(1000) ;
+ protected MultiMap m_suffixEntry = new MultiHashMap() ;
+
+
+ /**
+ * Gets the normalized suffix name of this BackendModule. The name is the
+ * normalized name found in the configuration for the backend within the
+ * suffix tag.
+ *
+ * @return the normalized suffix name for this BackendModule
+ */
+ public Name getSuffix()
+ {
+ return m_suffix ;
+ }
+
+
+ public Schema getSchema()
+ {
+ return m_schema ;
+ }
+
+
+ public boolean isReadOnly()
+ {
+ return this.m_isReadOnly ;
+ }
+
+
+ public void setReadOnly(boolean a_isReadOnlyMode)
+ {
+ this.m_isReadOnly = a_isReadOnlyMode ;
+ }
+
+
+ public void setEntryCacheSize(int a_numMaxEntries)
+ throws BackendException
+ {
+ this.m_cache.setMaximumSize(a_numMaxEntries) ;
+ }
+
+
+ public String getWorkingDirPath()
+ {
+ return this.m_wkdirPath ;
+ }
+
+
+ /**
+ * Sets the working directory path for implementation specific files or logs
+ * if any.
+ *
+ * @param a_dirPath the absolute path to the working directory for the
+ * configurable backend
+ * @throws BackendException if the configurable module has started and is
+ * not Reconfigurable.
+ */
+ public void setWorkingDirPath(String a_dirPath)
+ throws BackendException
+ {
+ if (hasStarted()) {
+ throw new BackendException("Cannot change working directory path "
+ + "after backend has started!") ;
+ }
+
+ File l_dir = new File(a_dirPath) ;
+
+ if (!l_dir.exists()) {
+ throw new BackendException(a_dirPath + " does not exist") ;
+ } else if (!l_dir.canWrite()) {
+ throw new BackendException("Cannot read " + a_dirPath) ;
+ } else if (!l_dir.canWrite()) {
+ throw new BackendException("Cannot write to " + a_dirPath) ;
+ } else if (!l_dir.isDirectory()) {
+ throw new BackendException(a_dirPath + " is not a directory.") ;
+ }
+
+ this.m_wkdirPath = l_dir.getAbsolutePath() ;
+ }
+
+
+ public void setAdminUserDN(Name an_adminDN)
+ throws BackendException
+ {
+ this.m_adminUser = an_adminDN ;
+ }
+
+
+ public Name getAdminUserDN()
+ {
+ return m_adminUser ;
+ }
+
+
+ public void setAdminUserPassword(String an_adminPassword)
+ throws BackendException
+ {
+ this.m_adminPassword = an_adminPassword ;
+ }
+
+
+ public String getAdminUserPassword()
+ {
+ return this.m_adminPassword ;
+ }
+
+
+ public int getEntryCacheSize()
+ {
+ return this.m_cache.getMaximumSize() ;
+ }
+
+
+ public void initialize()
+ throws Exception
+ {
+ if(hasEntry(getSuffix())) {
+ getLogger().info("Suffix entry exists skipping initial creation!") ;
+ return ;
+ }
+
+ getLogger().info("Suffix entry DOES NOT EXIST! " +
+ "Creating Suffix entry for the first time.") ;
+
+ // Extract User Provided Distinguished Name and create the new suffix
+ // root entry.
+ Collection l_col = (Collection) m_suffixEntry.get(Schema.DN_ATTR) ;
+ if(l_col == null) {
+ l_col = (Collection) m_suffixEntry.get("dn") ;
+ }
+ if(l_col == null) {
+ throw new BackendException("Cannot find a 'distinguishedName' or "
+ + "'dn' attribute in the suffix entry!") ;
+ }
+ String l_updn = (String) l_col.iterator().next() ;
+
+ LdapEntry l_entry = newEntry(l_updn) ;
+ Iterator l_keys = m_suffixEntry.keySet().iterator() ;
+ while(l_keys.hasNext()) {
+ String l_key = (String) l_keys.next() ;
+ if(l_key.toLowerCase().trim().equals(Schema.DN_ATTR) ||
+ l_key.toLowerCase().trim().equals("dn"))
+ {
+ continue ;
+ }
+
+ Iterator l_values = ((Collection)
+ m_suffixEntry.get(l_key)).iterator() ;
+ while(l_values.hasNext()) {
+ l_entry.addValue(l_key, l_values.next()) ;
+ }
+ }
+
+ create(l_entry) ;
+ }
+
+
+ /**
+ * All derived modules should call super.service first.
+ */
+ public void service(ServiceManager a_manager)
+ throws ServiceException
+ {
+ m_schemaManager
+ = (SchemaManager) a_manager.lookup(SchemaManager.ROLE) ;
+ m_nexus = (UnifiedBackend) a_manager.lookup(UnifiedBackend.ROLE) ;
+ }
+
+
+ public void start()
+ throws Exception
+ {
+ super.start() ;
+ m_nexus.register( this ) ;
+ }
+
+
+ public void stop()
+ throws Exception
+ {
+ m_nexus.unregister( this ) ;
+ super.stop() ;
+ }
+
+
+ public void registerClientManager( ClientManager a_manager )
+ {
+ m_clientMan = a_manager ;
+ }
+
+
+ ////////////////////////////////////////////
+ // Configuration Interface Implementation //
+ ////////////////////////////////////////////
+
+
+ /** DN of backend suffix property tag. */
+ public static final String SUFFIX_NODE = "suffix" ;
+ /** Admin user dn property tag. */
+ public static final String ADMINDN_NODE = "adminUserDN" ;
+ /** Admin user password property tag. */
+ public static final String ADMINPW_NODE = "adminUserPassword" ;
+ /** Working directory path property tag. */
+ public static final String WDIR_NODE = "workingDirPath" ;
+ /** Entry cache size property tag. */
+ public static final String CACHESZ_NODE = "entryCacheSize" ;
+
+
+ /**
+ * Avalon Configurable interface implementation. Here's an example
+ * configuration:<br>
+ * <config>
+ * <backend>
+ * <!-- mandatory -->
+ * <suffix>dc=domain,dc=com</suffix>
+ *
+ * <!-- mandatory -->
+ * <adminUserDN>cn=admin,dc=domain,dc=com</adminUserDN>
+ *
+ * <!-- mandatory -->
+ * <adminUserPassword>secret</adminUserPassword>
+ *
+ * <!-- mandatory -->
+ * <workingDirPath>var/backend0</workingDirPath>
+ *
+ * <!-- optional -->
+ * <entryCacheSize>100</entryCacheSize>
+ * </backend>
+ * </config>
+ *
+ * @param a_config an avalon configuration object for this backend block.
+ * @throws ConfigurationException if the configuration is not correct.
+ */
+ public void configure( Configuration a_config )
+ throws ConfigurationException
+ {
+ Configuration l_suffixConfig = a_config.getChild( SUFFIX_NODE, false ) ;
+ if( l_suffixConfig == null )
+ {
+ throw new ConfigurationException( "Encountered module config with "
+ + "missing <" + SUFFIX_NODE+ "> tag! Cannot process "
+ + "config without unique backend suffix name." ) ;
+ }
+
+ // Got through all the attributes and add it to the suffix multimap
+ Configuration [] l_attributes = l_suffixConfig.getChildren() ;
+ for( int ii = 0 ; ii < l_attributes.length ; ii++ )
+ {
+ String l_name = l_attributes[ii].getAttribute( "name", null ) ;
+ String l_value = l_attributes[ii].getAttribute( "value", null ) ;
+
+ if( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug( "Adding suffix attribute " + l_name
+ + " with value " + l_value ) ;
+ }
+
+ m_suffixEntry.put( l_name, l_value ) ;
+ }
+
+ if( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug( "Dumping suffix entry:\n" + m_suffixEntry ) ;
+ }
+
+ // Check multimap for the long and short names of 'dn' and complain if
+ // this or 'distinguishedName' keys do not exist.
+ Collection l_dnVals = ( Collection )
+ m_suffixEntry.get( Schema.DN_ATTR ) ;
+ if( l_dnVals == null )
+ {
+ l_dnVals = ( Collection ) m_suffixEntry.get( "dn" ) ;
+ }
+ if( l_dnVals == null )
+ {
+ throw new ConfigurationException( "Encountered module config with a"
+ + " missing attribute for the dn! Cannot process config without"
+ + " unique backend suffix distinguished name." ) ;
+ }
+
+ String l_suffix = null ;
+ try
+ {
+ l_suffix = ( String ) l_dnVals.iterator().next() ;
+ }
+ catch( NoSuchElementException e )
+ {
+ throw new ConfigurationException( "Encountered module config with a"
+ + " missing value for the dn! Cannot process config without"
+ + " unique backend suffix distinguished name.") ;
+ }
+ if( l_suffix == null || l_suffix.trim().equals( "" ) )
+ {
+ throw new ConfigurationException("Encountered module config with a "
+ + "missing value for the dn! Cannot process config without "
+ + "unique backend suffix distinguished name.") ;
+ }
+
+
+ try
+ {
+ m_schema = m_schemaManager.getSchema( l_suffix ) ;
+
+ if( m_schema == null )
+ {
+ throw new ConfigurationException( "Got a null schema from the "
+ + "schema manager using the suffix " + l_suffix ) ;
+ }
+ else if( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug( "Got schema for suffix " + l_suffix ) ;
+ }
+
+ m_suffix = m_schema.getNormalizingParser().parse( l_suffix ) ;
+ }
+ catch( InvalidNameException e )
+ {
+ String l_msg = "The module suffix " + l_suffix
+ + " is not syntacticly correct: " ;
+ getLogger().error( l_msg, e ) ;
+ throw new ConfigurationException( l_msg, e ) ;
+ }
+ catch( NameNotFoundException e )
+ {
+ String l_msg = "Schema manager does not recognize this suffix: "
+ + l_suffix ;
+ getLogger().error( l_msg, e ) ;
+ throw new ConfigurationException( l_msg, e ) ;
+ }
+ catch( NamingException e )
+ {
+ String l_msg = "Schema manager does not recognize this suffix: "
+ + l_suffix ;
+ getLogger().error( l_msg, e ) ;
+ throw new ConfigurationException( l_msg, e ) ;
+ }
+
+
+ String l_adminUserDn =
+ a_config.getChild( ADMINDN_NODE ).getValue( null ) ;
+ if( l_adminUserDn == null )
+ {
+ throw new ConfigurationException( "Encountered "
+ + getImplementationName()
+ + " module config for suffix " + m_suffix + " with missing <"
+ + ADMINDN_NODE
+ + "> tag! Cannot process config without this mandatory tag." ) ;
+ }
+
+ try
+ {
+ m_adminUser =
+ m_schema.getNormalizingParser().parse( l_adminUserDn ) ;
+ }
+ catch( NamingException e )
+ {
+ throw new ConfigurationException( "Encountered "
+ + getImplementationName()
+ + " module config for suffix " + m_suffix + " with bad <"
+ + this.ADMINDN_NODE + "> tag! Cannot process config without "
+ + "this mandatory tag being present with a valid DN" ) ;
+ }
+
+ m_adminPassword = a_config.getChild( ADMINPW_NODE ).getValue( null ) ;
+ if( m_adminPassword == null )
+ {
+ throw new ConfigurationException( "Encountered "
+ + getImplementationName()
+ + " module config for suffix " + m_suffix + " with missing <"
+ + ADMINPW_NODE
+ + "> tag! Cannot process config without this mandatory tag." ) ;
+ }
+
+ m_wkdirPath = m_context.getBaseDirectory().getAbsolutePath()
+ + File.separator + a_config.getChild( WDIR_NODE ).getValue( null ) ;
+ File l_dir = new File( m_wkdirPath ) ;
+ if( ! l_dir.exists() )
+ {
+ l_dir.mkdirs() ;
+ }
+
+ if( m_wkdirPath == null )
+ {
+ throw new ConfigurationException( "Encountered "
+ + getImplementationName()
+ + " module config for suffix " + m_suffix + " with missing <"
+ + WDIR_NODE
+ + "> tag! Cannot process config without this mandatory tag." ) ;
+ }
+
+ m_cache.setMaximumSize( a_config.getChild( CACHESZ_NODE ).
+ getValueAsInteger( DEFAULT_ENTRY_CACHESZ ) ) ;
+ }
+
+
+ /**
+ * Looks up the BlockContext to get the base directory for the application.
+ */
+ public void contextualize( Context a_context )
+ throws ContextException
+ {
+ super.contextualize( a_context ) ;
+
+ try
+ {
+ m_context = ( BlockContext ) a_context ;
+ if( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug( "Got handle on block context with base "
+ + "directory "
+ + m_context.getBaseDirectory().getAbsolutePath() ) ;
+ }
+ }
+ catch( ClassCastException e )
+ {
+ getLogger().debug( "Context is not an instance of BlockContext!" ) ;
+ throw new ContextException(
+ "Context is not an instance of BlockContext!", e ) ;
+ }
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/Cursor.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/Cursor.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,424 @@
+/*
+ * $Id: Cursor.java,v 1.7 2003/03/13 18:26:44 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend ;
+
+
+import java.util.ArrayList ;
+import java.util.Observable ;
+import java.util.Enumeration ;
+
+import javax.naming.NamingException ;
+import javax.naming.NamingEnumeration ;
+
+import org.apache.avalon.framework.logger.Logger ;
+import org.apache.avalon.framework.logger.LogEnabled ;
+import java.util.Iterator;
+
+
+/**
+ * Cursors are automagically closing server-side NamingEnumerations.
+ *
+ * Their open/closed state changes are comunicated to their Observers which
+ * are usually the backends that created them.
+ * <br><br>
+ * Backend implementors are required to have at least one concrete Cursor
+ * implementation. To do so requires the definition of three protected methods:
+ * <br>
+ * <br>
+ * <code> freeResources: </code>
+ * Cursors are potentially valuble resources to a backend and hence generally
+ * need to free up their own resources when exhausted. The mechanism if any to
+ * free such resources will be specific to the backend's implementation. Cursor
+ * implementors are hence required to provide a protected <code>freeResources
+ * </code> method which is called whenever <code>close</code> is called on
+ * an open cursor. Hence, <code>freeResources</code> can only be called once
+ * by calls to <code>close</code>. The <code>freeResources</code>
+ * implementation should not make calls to the <code>close</code> method.
+ * Cursors automatically close themselves when they detect the consumption of
+ * all elements via calls to NamingEnumeration interfaces.
+ * <br><br>
+ * <code> advance</code>
+ * Backend failures need to propagate forward without breaking the Enumeration
+ * interface contract. Unfortunately enumerations do not allow generic
+ * exception handling while getting the next element. To work around this
+ * problem while also supporting NamingEnumeration methods, we require concrete
+ * cursor implementations to define an <code>advance</code> method
+ * implementation. Rather than place iteration code within the
+ * <code>nextElement</code> implementation which is final and hence cannot be
+ * overridden by subclasses, implementors must use the protected <code>advance
+ * </code> method. In fact, the <code>nextElement</code>
+ * implementation delegates calls to the <code>advance</code> method by
+ * wrapping the invokation with a BackendException/NamingException try catch
+ * which transduces the BackendExceptions and NamingExceptions into a subclass
+ * of NoSuchElementException (a.k.a a CursorException).
+ * <br><br>
+ * <code> canAdvance</code>
+ * Tests to see if this Cursor can advance will most likely be backend specific
+ * and may in some implementations throw a BackendException. To facilitate the
+ * automatic close of cursors on list consumption and backend exceptions <code>
+ * hasMoreElement</code> has been defined as a final method that wraps calls
+ * to <code>canAdvance</code>. Unlike the <code>advance</code> method
+ * backend exceptions are not transduced.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.7 $
+ *
+ * @see CursorException
+ * @see NamingEnumeration
+ */
+public abstract class Cursor extends Observable
+ implements // Cursors enumerate records
+ NamingEnumeration, // Cursors can & should be closed
+ LogEnabled // Cursors can be enabled to log
+{
+ public static boolean debug = false ;
+ /** Tracks this Cursors closed/open state. */
+ private boolean m_isClosed = false ;
+ /** Logger used by this Cursor */
+ private Logger m_logger = null ;
+ /** Cursor Listener List */
+ private ArrayList m_listeners = new ArrayList() ;
+
+
+ /////////////////////////////////////////
+ // LogEnabled Interface Implementation //
+ /////////////////////////////////////////
+
+
+ /**
+ * Sets the logger used by this Cursor which most probably will be set by
+ * its backend (factory).
+ *
+ * @param a_logger the logger to be used by this Cursor.
+ */
+ public void enableLogging(Logger a_logger)
+ {
+ m_logger = a_logger ;
+ }
+
+
+ /**
+ * Gets the logger used by this Cursor which most probably was inherited
+ * from its backend (factory).
+ *
+ * @return the logger used by this Cursor.
+ */
+ protected Logger getLogger()
+ {
+ return m_logger ;
+ }
+
+
+ ////////////////////////////////////////
+ // Closable Interface Implementations //
+ ////////////////////////////////////////
+
+
+ /**
+ * Gets whether this Cursor is currently open or closed.
+ *
+ * @return true if this Cursor is closed, otherwise false.
+ */
+ public final boolean isClosed()
+ {
+ return m_isClosed ;
+ }
+
+
+ /**
+ *
+ */
+ public final void close()
+ throws NamingException
+ {
+ if (!m_isClosed) {
+ m_isClosed = true ;
+ freeResources() ;
+ super.setChanged() ;
+ }
+ }
+
+
+ ///////////////////////////////////////////
+ // Enumeration Interface Implementations //
+ ///////////////////////////////////////////
+
+
+ /**
+ * Wrapper around advance which serves as an exception trap that transduces
+ * BackendExceptions into CursorExceptions (a subclass of the expected RT
+ * NoSuchElementException).
+ *
+ * @warning Invokations within the advance() implementations of subclasses
+ * will result in a never ending chain recursion.
+ * @return the next element in this Cursor.
+ * @side-effect Closes this cursor before throwing any exceptions.
+ */
+ public final Object nextElement()
+ {
+ if (m_isClosed) {
+ throw new CursorException("Cannot advance a closed cursor.") ;
+ }
+
+ Object l_element = null ;
+ try {
+ l_element = advance() ;
+
+ if (l_element == null) {
+ try {
+ close() ;
+ } catch(NamingException ne) {
+ if( null != m_logger ) {
+ m_logger.error("Failed to close this cursor on null return"
+ + " from advance():", ne) ;
+ }
+ }
+
+ throw new
+ CursorException("Cursor advance returned null element!") ;
+ }
+
+ if(m_listeners.size() > 0) {
+ Iterator l_list = m_listeners.iterator() ;
+ CursorEvent l_event = new CursorEvent(this, l_element) ;
+
+ while(l_list.hasNext()) {
+ CursorListener l_listener = (CursorListener) l_list.next() ;
+ l_listener.cursorAdvanced(l_event) ;
+ }
+ }
+
+ return l_element ;
+ } catch (BackendException e) {
+ if( null != m_logger ) {
+ m_logger.error("Backing store errors resulted in cursor failure " +
+ "closing cursor:", e) ;
+ }
+
+ try {
+ close() ;
+ } catch(NamingException ne) {
+ if( null != m_logger ) {
+ m_logger.error("Failed to close this cursor on error:", ne) ;
+ }
+ }
+
+ throw new CursorException(e) ;
+ } catch (NamingException ne) {
+ if( null != m_logger ) {
+ m_logger.error("Failed on advance() closing cursor: ", ne) ;
+ }
+
+ try {
+ close() ;
+ } catch(NamingException ne2) {
+ if( null != m_logger ) {
+ m_logger.error("Failed to close this cursor on error:", ne2) ;
+ }
+ }
+
+ throw new CursorException(ne) ;
+ }
+ }
+
+
+ /**
+ * Wrapper around advance which serves as an exception trap that transduces
+ * BackendExceptions into CursorExceptions (a subclass of the expected RT
+ * NoSuchElementException).
+ *
+ * @warning Invokations within the advance() implementations of subclasses
+ * will result in a never ending chain recursion.
+ * @return the next element in this Cursor.
+ * @side-effect Closes this cursor before throwing any exceptions.
+ */
+ public final Object next()
+ throws NamingException
+ {
+ if (m_isClosed) {
+ throw new CursorException("Cannot advance a closed cursor.") ;
+ }
+
+ Object l_element = null ;
+ try {
+ l_element = advance() ;
+
+ if (l_element == null) {
+ close() ;
+ throw new
+ CursorException("Cursor advance returned null element!") ;
+ }
+
+ return l_element ;
+ } catch (BackendException e) {
+ if( null != m_logger ) {
+ m_logger.error("Backing store errors resulted in cursor failure " +
+ "closing cursor:", e) ;
+ }
+ close() ;
+ throw new CursorException(e) ;
+ }
+ }
+
+
+ /**
+ * Wrapper around canAdvance which serves as means to close this Cursor
+ * when the enumeration completes or an exception is encountered.
+ *
+ * @warning Invokations within the canAdvance implementations of subclasses
+ * will result in a never ending chain recursion.
+ * @return true if there exists a next element in this Cursor, else false
+ * @side-effect Closes this cursor if canAdvance() returns false or if it
+ * encounters a BackendException on the call to canAdvance().
+ */
+ public final boolean hasMoreElements()
+ {
+ if (m_isClosed) {
+ return false ;
+ }
+
+ try {
+ if (!canAdvance()) {
+ try {
+ if( null != m_logger ) {
+ if(m_logger.isDebugEnabled() && debug) {
+ m_logger.debug("Automagically closing exhausted "
+ + "cursor.") ;
+ }
+ }
+
+ close() ;
+ } catch(NamingException ne) {
+ if( null != m_logger ) {
+ m_logger.error("Failed close upon exhausting cursor.", ne);
+ }
+ }
+
+ return false ;
+ }
+
+ return true ;
+ } catch (BackendException e) {
+ if( null != m_logger ) {
+ m_logger.error("Backend errors closing cursor prematurely", e) ;
+ }
+
+ try {
+ close() ;
+ } catch(NamingException ne) {
+ if( null != m_logger ) {
+ m_logger.error("Failed close upon backend error:", ne) ;
+ }
+ }
+
+ return false ;
+ } catch (NamingException e) {
+ if( null != m_logger ) {
+ m_logger.error("Naming errors closing cursor prematurely", e) ;
+ }
+
+ try {
+ close() ;
+ } catch(NamingException ne) {
+ if( null != m_logger ) {
+ m_logger.error("Failed close upon backend error:", ne) ;
+ }
+ }
+
+ return false ;
+ }
+ }
+
+
+ /**
+ * Wrapper around canAdvance which serves as a means to close this Cursor
+ * when the enumeration completes or an exception is encountered.
+ *
+ * @warning Invokations within the canAdvance implementations of subclasses
+ * will result in a never ending chain recursion.
+ * @return true if there exists a next element in this Cursor, else false
+ * @side-effect Closes this cursor if canAdvance() returns false or if it
+ * encounters a BackendException on the call to canAdvance().
+ */
+ public final boolean hasMore()
+ throws NamingException
+ {
+ if (m_isClosed) {
+ return false ;
+ }
+
+ try {
+ if (!canAdvance()) {
+ if( null != m_logger ) {
+ if(m_logger.isDebugEnabled() && debug) {
+ m_logger.debug("Automagically closing exhausted cursor.") ;
+ }
+ }
+
+ close() ;
+ return false ;
+ }
+
+ return true ;
+ } catch (BackendException e) {
+ if( null != m_logger ) {
+ m_logger.error("Backend errors closing cursor prematurely", e) ;
+ }
+ close() ;
+ return false ;
+ }
+ }
+
+
+ //////////////////////
+ // Abstract Methods //
+ //////////////////////
+
+
+ /**
+ * Delagate method called by hasMore[Elements] to test if we can move
+ * forward. Use this method to hold the code that would have normally gone
+ * into the hasMore[Elements] body. Unlike the hasMore[Elements] method the
+ * method allows the backend developer to throw backend specific exceptions
+ * which are eventually transduced into an automatic close of this Cursor.
+ * After closing this Cursor BackendExceptions are not rethrown as runtime
+ * exceptions to maintain [Naming]Enumeration semantics.
+ *
+ * @return true if Cursor can move to next non null entry, false otherwise.
+ * @throws BackendException when a error occurs on the entry backing store.
+ */
+ protected abstract boolean canAdvance()
+ throws BackendException, NamingException ;
+
+
+ /**
+ * Delagate method called by next[Element] to move this Cursor one element
+ * forward. Use this method to hold the code that would have normally gone
+ * into the next[Element] body. Unlike the next[Element] method this method
+ * allows the backend developer to throw backend specific exceptions.
+ * BackendExceptions (which are not runtime exceptions) are transduced into
+ * CursorExceptions (which are runtime exceptions derived from
+ * NoSuchElementException).
+ *
+ * @return the element pointed to by this Cursor after advancing a step.
+ * @throws BackendException when a error occurs on the entry backing store.
+ */
+ protected abstract Object advance()
+ throws BackendException, NamingException ;
+
+
+ /**
+ * Called only once on cursor close to free up resources held by this
+ * Cursor.
+ */
+ protected abstract void freeResources() ;
+}
+
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/CursorEvent.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/CursorEvent.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,39 @@
+/*
+ * $Id: CursorEvent.java,v 1.2 2003/03/13 18:26:47 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend ;
+
+
+import java.util.EventObject;
+
+
+public class CursorEvent
+ extends EventObject
+{
+ public final Object element ;
+
+ CursorEvent(final Cursor a_cursor, final Object a_element)
+ {
+ super(a_cursor) ;
+
+ element = a_element ;
+ }
+
+
+ Cursor getCursorSource()
+ {
+ return (Cursor) this.source ;
+ }
+
+
+ Object getElement()
+ {
+ return element ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/CursorException.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/CursorException.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,73 @@
+/*
+ * $Id: CursorException.java,v 1.2 2003/03/13 18:26:49 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend ;
+
+
+import java.util.NoSuchElementException ;
+
+
+/**
+ * This exception is thrown when Cursor has no more elements to return.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.2 $
+ */
+public class CursorException
+ extends NoSuchElementException
+{
+ /** Nested exception if any. */
+ private final Throwable m_error ;
+
+
+ /**
+ * Constructs an Exception with a nested Throwable whose message is
+ * used to compose this exceptions message.
+ *
+ * @param an_exception a backend exception to wrap.
+ */
+ public CursorException(Throwable an_exception)
+ {
+ super(an_exception.toString()) ;
+ this.m_error = an_exception ;
+ }
+
+ /**
+ * Constructs an Exception without a message and without a Throwable.
+ */
+ public CursorException()
+ {
+ super() ;
+ this.m_error = null ;
+ }
+
+ /**
+ * Constructs an Exception with a detailed message.
+ *
+ * @param a_message The message associated with the exception.
+ */
+ public CursorException(String a_message)
+ {
+ super(a_message) ;
+ this.m_error = null ;
+ }
+
+
+ /**
+ * Checks to see if this exception was due to a backend/database error.
+ *
+ * @return true if a Throwable is wrapped by this exception or false
+ * otherwise.
+ */
+ public boolean isError()
+ {
+ return this.m_error != null ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/CursorListener.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/CursorListener.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,20 @@
+/*
+ * $Id: CursorListener.java,v 1.2 2003/03/13 18:26:50 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend ;
+
+
+import java.util.EventListener ;
+
+
+public interface CursorListener
+ extends EventListener
+{
+ void cursorAdvanced(CursorEvent an_event) ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/EmptyCursor.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/EmptyCursor.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,49 @@
+/*
+ * $Id: EmptyCursor.java,v 1.2 2003/03/13 18:26:51 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend ;
+
+
+import java.util.NoSuchElementException ;
+
+
+/**
+ * An empty cursor that is closed on creation! Used as annon inner class in so
+ * many places I had to create it.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.2 $
+ */
+public class EmptyCursor
+ extends Cursor
+{
+ /**
+ * Closes on creation.
+ */
+ public EmptyCursor()
+ {
+ try { close() ; } catch(Exception e) {} ;
+ }
+
+ /**
+ * Throws NoSuchElementException all the time.
+ */
+ public Object advance() { throw new NoSuchElementException() ; }
+
+ /**
+ * Always returns false.
+ */
+ public boolean canAdvance() { return false ; }
+
+ /**
+ * Does nothing.
+ */
+ public void freeResources() { }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/EnumerationCursor.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/EnumerationCursor.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,61 @@
+/*
+ * $Id: EnumerationCursor.java,v 1.2 2003/03/13 18:26:52 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend ;
+
+
+import java.util.Enumeration ;
+
+
+/**
+ * A cursor using an underlying Enumeration.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.2 $
+ */
+public class EnumerationCursor
+ extends Cursor
+{
+ private final Enumeration m_enumeration ;
+
+ /**
+ * Creates a cursor over an Enumeration.
+ *
+ * @param a_enumeration the underlying Enumeration this cursor uses.
+ */
+ public EnumerationCursor(Enumeration a_enumeration)
+ {
+ m_enumeration = a_enumeration ;
+ }
+
+
+ /**
+ * Returns enumeration.nextElement()
+ * @return enumeration.nextElement()
+ */
+ public Object advance()
+ {
+ return m_enumeration.nextElement() ;
+ }
+
+
+ /**
+ * Returns enumeration.hasMoreElements()
+ * @return Returns enumeration.hasMoreElements()
+ */
+ public boolean canAdvance()
+ {
+ return m_enumeration.hasMoreElements() ;
+ }
+
+
+ /** Does nothing */
+ public void freeResources() { }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/IteratorCursor.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/IteratorCursor.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,55 @@
+/*
+ * $Id: IteratorCursor.java,v 1.2 2003/03/13 18:26:54 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend ;
+
+
+import java.util.Iterator ;
+
+
+/**
+ * A cursor using an underlying Iterator.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.2 $
+ */
+public class IteratorCursor
+ extends Cursor
+{
+ private final Iterator m_iterator ;
+
+ /**
+ * Creates a cursor over an Iterator.
+ *
+ * @param a_iterator the underlying iterator this cursor uses.
+ */
+ public IteratorCursor(Iterator a_iterator)
+ {
+ m_iterator = a_iterator ;
+ }
+
+
+ /** Returns iterator.next() */
+ public Object advance()
+ {
+ return m_iterator.next() ;
+ }
+
+
+ /** Returns iterator.hasNext() */
+ public boolean canAdvance()
+ {
+ return m_iterator.hasNext() ;
+ }
+
+
+ /** Does nothing */
+ public void freeResources() { }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/LdapEntry.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/LdapEntry.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,297 @@
+/*
+ * $Id: LdapEntry.java,v 1.8 2003/03/13 18:26:55 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend ;
+
+import java.math.BigInteger ;
+import java.io.Serializable ;
+
+import java.util.Date ;
+import java.util.Collection ;
+
+import javax.naming.Name ;
+import javax.naming.directory.SchemaViolationException ;
+import javax.naming.directory.AttributeModificationException ;
+import javax.naming.directory.InvalidAttributeValueException ;
+import javax.naming.directory.InvalidAttributeIdentifierException ;
+import javax.naming.directory.AttributeInUseException ;
+import java.util.Iterator;
+import org.apache.eve.schema.Schema;
+import javax.naming.NamingException;
+
+
+/**
+ * Internal server side representation of an LDAP entry. All backend entry
+ * implementations are expected to implement this interface. The interface
+ * defines standard house keeping attributes used by this LDAP v3
+ * implementation.
+ *
+ * @task We need to explicitly outline some semantics for the various house
+ * keeping constants - like the parent id of the suffix entry should always be
+ * itself etc.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.8 $
+ * @see Backend
+ */
+public interface LdapEntry
+ extends Serializable
+{
+ /**
+ * The identifier of the Distinguished name attribute for this entry. The
+ * value of this attribute is NOT a normalized DN it is the user provide
+ * DN.
+ *
+ * @see getEntryDN
+ */
+ String DN_ATTR = Schema.DN_ATTR ;
+ /**
+ * The identifier of the normalized Distinguished name attribute for this
+ * Entry's parent.
+ *
+ * @see getParentDN
+ */
+ String PARENTDN_ATTR = "parentdn" ;
+ /**
+ * The identifier of the normalized Distinguished name attribute for this
+ * Entry's subschema subentry.
+ *
+ * @see getSubschemaSubentry
+ */
+ String SUBSCHEMASUBENTRY_ATTR = "subschemasubentry" ;
+ /**
+ * The identifier of the normalized Distinguished name attribute for this
+ * Entry's creator.
+ *
+ * @see getCreatorsName
+ */
+ String CREATORSNAME_ATTR = "creatorsname" ;
+ /**
+ * The identifier of the normalized Distinguished name attribute for this
+ * Entry's last modifier.
+ *
+ * @see getModifiersName
+ */
+ String MODIFIERSNAME_ATTR = "modifiersname" ;
+ /** Unique entry identifier attribute's name */
+ String ID_ATTR = "entryid" ;
+ /** Entry's parent id attribute's identifier */
+ String PARENTID_ATTR = Schema.HIERARCHY_ATTR ;
+ /** Number of subordinates attribute's identifier */
+ String NUMSUBORDINATES_ATTR = "numsubordinates" ;
+ /** Create timestamp attribute's identifier */
+ String CREATETIMESTAMP_ATTR = "createtimestamp" ;
+ /** Modifier's timestamp attribute's identifier */
+ String MODIFYTIMESTAMP_ATTR = "modifytimestamp" ;
+
+ Collection attributes() ;
+
+ boolean hasAttribute(String an_attributeName) ;
+
+ /**
+ * Checks whether or not this Entry is a valid entry residing within a
+ * backend. Entries are validated on successful create() calls. When
+ * Entry instances are initialized in the java sense via the newEntry()
+ * call on backends, they are in the invalid state.
+ *
+ * @return true if this entry has been persisted to a backend,
+ * false otherwise.
+ */
+ boolean isValid() ;
+
+ /**
+ * Gets this entry's creation timestamp as a Date.
+ *
+ * @return Date representing the creation timestamp of this entry.
+ */
+ Date getCreateTimestamp() ;
+
+ /**
+ * Gets this entry's modification timestamp as a Date.
+ *
+ * @return Date representing the timestamp this entry was last modified.
+ */
+ Date getModifyTimestamp() ;
+
+ /**
+ * Gets the unique distinguished name associated with this entry as it was
+ * supplied during creation without whitespace trimming or character case
+ * conversions. This version of the DN is kept within the body of this
+ * Entry as an operational attribute so that it could be returned as it was
+ * given to the server w/o normalization effects: case and whitespace will
+ * be entact.
+ *
+ * @return the distinguished name of this entry as a String.
+ */
+ String getEntryDN() ;
+
+ /**
+ * Gets the normalized unique distinguished name associated with this
+ * entry. This DN unlike the user specified DN accessed via getDN() is not
+ * an operational attribute composing the body of this Entry.
+ *
+ * The distinguished name is presumed to be normalized by the server naming
+ * subsystem in accordance with schema attribute syntax and attribute
+ * matching rules. The DN is also presumed to be syntacticly correct and
+ * within the namespace of this directory information base from which this
+ * Entry originated.
+ *
+ * @return the normalized distinguished name of this entry as a String.
+ */
+ Name getNormalizedDN()
+ throws NamingException ;
+
+ Name getUnNormalizedDN()
+ throws NamingException ;
+
+ /**
+ * Gets the normalized unique distinguished name of this Entry's parent.
+ *
+ * The distinguished name is presumed to be normalized by the server naming
+ * subsystem in accordance with schema attribute syntax and attribute
+ * matching rules. The DN is also presumed to be syntacticly correct and
+ * within the namespace of this directory information base from which this
+ * Entry originated.
+ *
+ * @return the normalized distinguished name of this Entry's parent.
+ */
+ String getParentDN() ;
+
+ /**
+ * Gets the distinguished name of the creator of this entry.
+ *
+ * The distinguished name is presumed to be normalized by the server naming
+ * subsystem in accordance with schema attribute syntax and attribute
+ * matching rules. The DN is also presumed to be syntacticly correct and
+ * within the namespace of this directory information base from which this
+ * Entry originated.
+ *
+ * @return the distinguished name of the creator.
+ */
+ String getCreatorsName() ;
+
+ /**
+ * Gets the distinguished name of the last modifier of this entry.
+ *
+ * The distinguished name is presumed to be normalized by the server naming
+ * subsystem in accordance with schema attribute syntax and attribute
+ * matching rules. The DN is also presumed to be syntacticly correct and
+ * within the namespace of this directory information base from which this
+ * Entry originated.
+ *
+ * @return the DN of the user to modify this entry last.
+ */
+ String getModifiersName() ;
+
+ Schema getSchema() ;
+
+ /**
+ * Gets the distinguished name of the subschema subentry for this Entry.
+ *
+ * The distinguished name is presumed to be normalized by the server naming
+ * subsystem in accordance with schema attribute syntax and attribute
+ * matching rules. The DN is also presumed to be syntacticly correct and
+ * within the namespace of this directory information base from which this
+ * Entry originated.
+ *
+ * @return String of the subschema subentry distinguished name.
+ */
+ String getSubschemaSubentryDN() ;
+
+ /**
+ * Gets a single valued attribute by name or returns the first value of a
+ * multivalued attribute.
+ *
+ * @param a_attribName the name of the attribute to lookup.
+ * @return an Object value which is either a String or byte [] or null if
+ * the attribute does not exist.
+ */
+ Object getSingleValue(String an_attribName) ;
+
+ /**
+ * Gets a multivalued attribute by name.
+ *
+ * @param a_attribName the name of the attribute to lookup.
+ * @return a Collection or null if no attribute value exists.
+ */
+ Collection getMultiValue(String an_attribName) ;
+
+ /**
+ * Adds a value to this Entry potentially resulting in more than one value
+ * for the attribute/key.
+ *
+ * @param an_attribName attribute name/key
+ * @param a_value the value to add
+ * @throws InvalidAttributeIdentifierException when an attempt is made to
+ * add to or create an attribute with an invalid attribute identifier.
+ * @throws InvalidAttributeValueException when an attempt is made to add to
+ * an attribute a value that conflicts with the attribute's schema
+ * definition. This could happen, for example, if attempting to add an
+ * attribute with no value when the attribute is required to have at least
+ * one value, or if attempting to add more than one value to a single
+ * valued-attribute, or if attempting to add a value that conflicts with
+ * the syntax of the attribute.
+ */
+ void addValue(String an_attribName, Object a_value)
+ throws
+ AttributeInUseException,
+ InvalidAttributeValueException,
+ InvalidAttributeIdentifierException ;
+
+ /**
+ * Removes the attribute/value pair in this Entry only without affecting
+ * other values that the attribute may have.
+ *
+ * @param an_attribName attribute name/key
+ * @param a_value the value to remove
+ * @throws AttributeModificationException when an attempt is made to modify
+ * an attribute, its identifier, or its values that conflicts with the
+ * attribute's (schema) definition or the attribute's state. Also thrown
+ * if the specified attribute name does not exist as a key in this Entry.
+ */
+ void removeValue(String an_attribName, Object a_value)
+ throws InvalidAttributeIdentifierException ;
+
+ /**
+ * Removes the specified set of attribute/value pairs in this Entry.
+ *
+ * @param an_attribName attribute name/key
+ * @param a_valueArray the set of values to remove
+ * @throws AttributeModificationException when an attempt is made to modify
+ * an attribute, its identifier, or its values that conflicts with the
+ * attribute's (schema) definition or the attribute's state. Also thrown
+ * if the specified attribute name does not exist as a key in this Entry.
+ */
+ void removeValues(String an_attribName, Object [] a_valueArray)
+ throws InvalidAttributeIdentifierException ;
+
+ /**
+ * Removes all the attribute/value pairs in this Entry associated with the
+ * attribute.
+ *
+ * @param an_attribName attribute name/key
+ * @param a_value the value to remove
+ * @throws AttributeModificationException when an attempt is made to modify
+ * an attribute, its identifier, or its values that conflicts with the
+ * attribute's (schema) definition or the attribute's state. Also thrown
+ * if the specified attribute name does not exist as a key in this Entry.
+ */
+ void removeValues(String an_attribName)
+ throws InvalidAttributeIdentifierException ;
+
+ /**
+ * Checks to see if this LdapEntry is equal to an entry with a Dn.
+ *
+ * @param a_dn the dn to test for equality.
+ * @return true if this entry has a Dn equal to a_dn, false otherwise.
+ */
+ boolean equals(String a_dn)
+ throws NamingException ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/NexusModule.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/NexusModule.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,730 @@
+/*
+ * $Id: NexusModule.java,v 1.26 2003/08/22 21:15:54 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend ;
+
+
+import org.apache.eve.AbstractModule ;
+
+import java.util.Map ;
+import java.util.Date ;
+import java.util.HashMap ;
+import java.util.Iterator ;
+
+import javax.naming.Name ;
+import javax.naming.NameParser ;
+import javax.naming.NamingException ;
+import javax.naming.InvalidNameException ;
+import javax.naming.NameNotFoundException ;
+
+import org.apache.ldap.common.name.LdapName ;
+import org.apache.ldap.common.filter.ExprNode ;
+
+import org.apache.eve.schema.Schema ;
+import org.apache.eve.client.ClientManager ;
+import org.apache.eve.schema.SchemaManager ;
+import org.apache.eve.client.ClientSession ;
+import org.apache.eve.client.ClientManagerSlave ;
+
+import org.apache.avalon.framework.ExceptionUtil ;
+import org.apache.avalon.framework.service.ServiceManager ;
+import org.apache.avalon.framework.service.ServiceException ;
+import org.apache.avalon.framework.configuration.Configuration ;
+import org.apache.avalon.framework.configuration.ConfigurationException ;
+
+
+/**
+ * Default backend nexus or unified backend implementation for the server.
+ *
+ * @phoenix:block
+ * @phoenix:service name="org.apache.eve.backend.UnifiedBackend"
+ * @phoenix:mx-topic name="backend-nexus"
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.26 $
+ */
+public class NexusModule
+ extends AbstractModule
+ implements UnifiedBackend, ClientManagerSlave
+{
+ /** Config tag for RootDSE definition */
+ public static final String ROOTDSE_TAG = "RootDSE" ;
+ /** Config tag for RootDSE attributes */
+ public static final String ATTRIBUTE_TAG = "attribute" ;
+
+ ClientManager m_clientMan = null ;
+ SchemaManager m_schemaMan = null ;
+ Schema m_schema = null ;
+ RootDSE m_rootDSE = null ;
+
+ /** Map of backend normalized suffix strings to backends */
+ Map m_backends = new HashMap() ;
+ Map m_repListeners = new HashMap() ;
+ Map m_adminUsers = new HashMap() ;
+
+
+ // -------------------------------------------------------
+ // Operational Attribute Management Methods
+ // -------------------------------------------------------
+
+
+ /**
+ * Sets an entries operational attributes based on client session parameters
+ * and whether or not the operation is a create or an update.
+ *
+ * @param an_entry the entry to add or alter the operational attributes of.
+ * @param isCreate true if op attrs are added for create or false for update
+ */
+ private void setOperationalAttributes( LdapEntry an_entry,
+ boolean isCreate ) throws BackendException, NamingException
+ {
+ String l_now = new Date().toGMTString() ;
+ String l_userDn = null ;
+ ClientSession l_session = m_clientMan.getClientSession() ;
+
+ if( null == l_session )
+ {
+ throw new BackendException(
+ "Cannot obtain client session object!" ) ;
+ }
+
+ // Get authenticated principal's Dn
+ l_userDn = l_session.getPrincipal().getDn().toString() ;
+
+ if( isCreate )
+ {
+ if( an_entry.hasAttribute( LdapEntry.CREATETIMESTAMP_ATTR ) )
+ {
+ an_entry.removeValues( LdapEntry.CREATETIMESTAMP_ATTR ) ;
+ }
+
+ if( an_entry.hasAttribute( LdapEntry.CREATORSNAME_ATTR ) )
+ {
+ an_entry.removeValues( LdapEntry.CREATORSNAME_ATTR ) ;
+ }
+
+ an_entry.addValue( LdapEntry.CREATETIMESTAMP_ATTR, l_now ) ;
+ an_entry.addValue( LdapEntry.CREATORSNAME_ATTR, l_userDn ) ;
+ }
+
+ if( an_entry.hasAttribute( LdapEntry.MODIFYTIMESTAMP_ATTR ) )
+ {
+ an_entry.removeValues( LdapEntry.MODIFYTIMESTAMP_ATTR ) ;
+ }
+
+ if( an_entry.hasAttribute( LdapEntry.MODIFIERSNAME_ATTR ) )
+ {
+ an_entry.removeValues( LdapEntry.MODIFIERSNAME_ATTR ) ;
+ }
+
+ an_entry.addValue( LdapEntry.MODIFYTIMESTAMP_ATTR, l_now ) ;
+ an_entry.addValue( LdapEntry.MODIFIERSNAME_ATTR, l_userDn ) ;
+ }
+
+
+ // -------------------------------------------------------
+ // CRUD Method Implementations
+ // -------------------------------------------------------
+
+
+ public void create( LdapEntry an_entry )
+ throws BackendException, NamingException
+ {
+ setOperationalAttributes ( an_entry, true ) ;
+ getBackend( an_entry.getNormalizedDN() ).create( an_entry ) ;
+ }
+
+
+ public LdapEntry newEntry( String a_dn )
+ throws BackendException, NamingException
+ {
+ return getBackend( getNormalizedName( a_dn ) ).newEntry( a_dn ) ;
+ }
+
+
+ public LdapEntry read( Name a_dn )
+ throws BackendException, NamingException
+ {
+ return getBackend(
+ getNormalizedName( a_dn.toString() ) ).read( a_dn ) ;
+ }
+
+
+ public void update(LdapEntry an_entry)
+ throws BackendException, NamingException
+ {
+ setOperationalAttributes (an_entry, false) ;
+ getBackend( an_entry.getNormalizedDN() ).update(an_entry) ;
+ }
+
+
+ public void delete( LdapEntry an_entry )
+ throws BackendException, NamingException
+ {
+ getBackend( an_entry.getNormalizedDN() ).delete( an_entry ) ;
+ }
+
+
+ public LdapEntry getParent(Name a_childDn)
+ throws BackendException, NamingException
+ {
+ return getBackend(a_childDn).getParent(a_childDn) ;
+ }
+
+
+ public boolean hasEntry(Name a_dn)
+ throws BackendException, NamingException
+ {
+ return getBackend(a_dn).hasEntry(a_dn) ;
+ }
+
+
+ public boolean isSuffix(LdapEntry an_entry)
+ {
+ try {
+ return getBackend(an_entry.getNormalizedDN()).isSuffix(an_entry) ;
+ } catch(NamingException e) {
+ // Should never really be thrown.
+ return false ;
+ }
+ }
+
+
+ public Name getNormalizedName(String a_name)
+ throws NamingException
+ {
+ return m_schema.getNormalizingParser().parse(a_name) ;
+ }
+
+
+ public Name getName(String a_name)
+ throws NamingException
+ {
+ return m_schema.getNameParser().parse(a_name) ;
+ }
+
+
+ /**
+ * V E R Y I N E F F I C I E N T
+ *
+ * This could be made much more efficient by hashing all the normalized
+ * admin user names against their backends in a hashmap and doing the
+ * lookup after converting the a_userDn arguement into its canonical form.
+ */
+ public boolean isAdminUser(Name a_userDn)
+ throws NamingException
+ {
+ if(m_adminUsers.containsKey(a_userDn.toString())) {
+ return true ;
+ }
+
+ return false ;
+ }
+
+
+ public RootDSE getRootDSE()
+ {
+ return m_rootDSE ;
+ }
+
+
+ public Cursor listChildren(Name a_parentDn)
+ throws BackendException, NamingException
+ {
+ return getBackend(a_parentDn).listChildren(a_parentDn) ;
+ }
+
+
+ public Cursor search(ExprNode a_searchFilter, Name a_baseDn,
+ int a_scope)
+ throws BackendException, NamingException
+ {
+ // Base search without a namespace returns the RootDSE within a
+ // SingletonCursor that returns only one entry: the RootDSE.
+ if(a_baseDn.toString().trim().equals("") && a_scope == BASE_SCOPE) {
+ return new SingletonCursor(m_rootDSE) ;
+ }
+
+ return getBackend(a_baseDn).search(a_searchFilter,
+ a_baseDn, a_scope) ;
+ }
+
+
+ /**
+ * Modifies the relative distinguished name (RDN) of an entry without
+ * changing any parent child relationships. This call has the side effect
+ * of altering the distinguished name of descendent entries if they exist.
+ * The boolean argument will optionally remove the existing RDN attribute
+ * value pair replacing it with the new RDN attribute value pair. If other
+ * RDN attribute value pairs exist besides the current RDN they will be
+ * spared.
+ *
+ * If the new Rdn and the old Rdn are equal this method does nothing.
+ *
+ * @param an_entry the entry whose RDN is to be modified.
+ * @param a_newRdn the new Rdn that is to replace the current Rdn.
+ * @param a_deleteOldRdn deletes the old Rdn attribute value pair if true.
+ * @throws BackendException when the operation cannot be performed due to a
+ * backing store error.
+ * @throws NamingException when naming violations and or schema violations
+ * occur due to attempting this operation.
+ */
+ public void modifyRdn( LdapEntry an_entry, Name a_newRdn,
+ boolean a_deleteOldRdn )
+ throws BackendException, NamingException
+ {
+ AtomicBackend l_be = getBackend( an_entry.getNormalizedDN() ) ;
+ Name l_dn = new LdapName( an_entry.getEntryDN() ) ;
+ String l_oldRdnStr = l_dn.get( l_dn.size() - 1 ) ;
+ String l_newRdnStr = a_newRdn.get( a_newRdn.size() - 1 ) ;
+
+ // Set common operational attributes on the entry first
+ setOperationalAttributes( an_entry, false ) ;
+
+ // Only perform modifyRdn operation if newRdn is not the same as old
+ if ( ! l_oldRdnStr.equals( l_newRdnStr ) )
+ {
+ l_be.modifyRdn( an_entry, a_newRdn, a_deleteOldRdn ) ;
+ }
+
+ getBackend(an_entry.getNormalizedDN()).
+ modifyRdn(an_entry, a_newRdn, a_deleteOldRdn) ;
+ }
+
+
+ /**
+ * This overload combines the first two method operations into one.
+ * It changes the Rdn and the parent prefix at the same time while
+ * recursing name changes to all descendants of the child entry. It
+ * is obviously more complex than the other two operations alone and
+ * involves changes to both parent child indices and DN indices.
+ *
+ * @param a_parentEntry the parent the child is to subordinate to.
+ * @param a_childEntry the child to be moved under the parent.
+ * @param a_newRdn the new Rdn that is to replace the current Rdn.
+ * @param a_deleteOldRdn deletes the old Rdn attribute value pair if true.
+ * @throws BackendException when the operation cannot be performed due to a
+ * backing store error.
+ * @throws NamingException when naming violations and or schema violations
+ * occur due to attempting this operation.
+ */
+ public void move( LdapEntry a_parentEntry, LdapEntry a_childEntry,
+ Name a_newRdn, boolean a_deleteOldRdn )
+ throws BackendException, NamingException
+ {
+ AtomicBackend l_be = getBackend( a_parentEntry.getNormalizedDN() ) ;
+ Name l_childDn = new LdapName( a_childEntry.getEntryDN() ) ;
+ String l_oldRdnStr = l_childDn.get( l_childDn.size() - 1 ) ;
+ String l_newRdnStr = a_newRdn.get( a_newRdn.size() - 1 ) ;
+
+ Name l_normalizedChildDn = a_childEntry.getNormalizedDN() ;
+ Name l_normalizedOldParentDn =
+ l_normalizedChildDn.getPrefix( l_normalizedChildDn.size() - 1 ) ;
+
+ // Set common operational attributes on the entry first
+ setOperationalAttributes( a_childEntry, false ) ;
+
+
+ if ( l_normalizedOldParentDn.equals( a_parentEntry.getNormalizedDN() ) )
+ {
+ if ( l_oldRdnStr.equals( l_newRdnStr ) )
+ {
+ /*
+ * The new and old rdn are the same and the new and old parents
+ * are the same as well so we do nothing. Both rdn renames and
+ * move operations are pointless so we return.
+ */
+ return ;
+ }
+
+ /*
+ * The move operation is unnecessary but the rdn change is valid
+ * so we transduce this call to a modifyRdn call on the backend
+ */
+ l_be.modifyRdn( a_childEntry, a_newRdn, a_deleteOldRdn ) ;
+ }
+ else
+ {
+ if ( l_oldRdnStr.equals( l_newRdnStr ) )
+ {
+ /*
+ * The new and old rdn are the same so we convert this to a
+ * simple move operation.
+ */
+ l_be.move( a_parentEntry, a_childEntry ) ;
+ }
+ else
+ {
+ // Both the move and the rdn change are necessary here!
+ l_be.move( a_parentEntry, a_childEntry, a_newRdn,
+ a_deleteOldRdn ) ;
+ }
+ }
+ }
+
+
+ /**
+ * Moves a child entry without changing the RDN under a new parent entry.
+ * This effects the parent child relationship between the parent entry and
+ * the child entry. The index for the child mapping it to the current
+ * parent is destroyed and a new index mapping it to the new parent is
+ * created. As a side effect the name of the child entry and all its
+ * descendants will reflect the move within the DIT to a new parent. The
+ * old parent prefix to the distinguished names of the child and its
+ * descendents will be replaced by the new parent DN prefix.
+ *
+ * If the new parent is the same as the old parent this call does nothing
+ * since the operation is pointless.
+ *
+ * @param a_parentEntry the parent the child is to subordinate to.
+ * @param a_childEntry the child to be moved under the parent.
+ * @throws BackendException when the operation cannot be performed due to a
+ * backing store error.
+ * @throws NamingException when naming violations and or schema violations
+ * occur due to attempting this operation.
+ */
+ public void move( LdapEntry a_parentEntry, LdapEntry a_childEntry )
+ throws BackendException, NamingException
+ {
+ AtomicBackend l_be = getBackend( a_parentEntry.getNormalizedDN() ) ;
+ Name l_dn = a_childEntry.getNormalizedDN() ;
+ Name l_oldParentDn = l_dn.getPrefix( l_dn.size() - 1 ) ;
+
+ // Fires ModifyProtocolEvent
+ setOperationalAttributes( a_childEntry, false ) ;
+
+ // Only perform operation if new parent dn is different from the old
+ if ( ! a_parentEntry.getNormalizedDN().equals( l_oldParentDn ) )
+ {
+ l_be.move( a_parentEntry, a_childEntry ) ;
+ }
+ }
+
+
+ //////////////////////////////////////////////
+ // UnifiedBackend Interface Implementations //
+ //////////////////////////////////////////////
+
+
+ /**
+ * Gets the suffix of the backend responsible for an entry using the entry's
+ * distinguished name.
+ *
+ * @phoenix:mx-operation
+ * @phoenix:mx-description Gets the suffix of the backend storing an entry
+ * by its DN.
+ */
+ public String getBackendSuffixForEntry(String a_dn)
+ throws InvalidNameException, NameNotFoundException
+ {
+ StringBuffer l_buf = new StringBuffer() ;
+
+ l_buf.append("Repsonsible backend module suffix for entry ") ;
+ l_buf.append(a_dn).append(':').append("\n") ;
+ l_buf.append("=================================") ;
+ l_buf.append("=================================\n") ;
+ l_buf.append("\n\n") ;
+
+ try {
+ Name l_dn = getNormalizedName (a_dn) ;
+ BackendModule l_be = (BackendModule) getBackend(l_dn) ;
+ l_buf.append(l_be.getImplementationName()).append("\n") ;
+ l_buf.append(l_be.getSuffix()).append("\n") ;
+ } catch(Throwable t) {
+ l_buf.append(ExceptionUtil.printStackTrace(t)) ;
+ }
+
+ return l_buf.toString() ;
+ }
+
+
+ /**
+ * Gets the most significant Dn that exists within the server and hence can
+ * be matched to an actual entry.
+ *
+ * @param a_dn to use for the matching test.
+ * @return the matching portion of a_dn, or the valid empty string dn if no
+ * match was found.
+ */
+ public Name getMatchedDn( Name a_dn )
+ throws NamingException, BackendException
+ {
+ LdapName l_suffix ;
+
+ // Don't try to match for the empty dn which matches by default if we
+ // try to match it in hasEntry then we will get a failure to find an
+ // atomic backend for it.
+ if( a_dn.size() == 0 )
+ {
+ return a_dn ;
+ }
+ // Return if a_dn itself is matched/exists.
+ else if( hasEntry( a_dn ) )
+ {
+ return a_dn ;
+ }
+
+ // Otherwise we start removing most significant components from the head
+ // of it looking for a suffix dn that matches until the "" dn results
+ l_suffix = ( LdapName ) a_dn.clone() ;
+ while( l_suffix.size() > 0 )
+ {
+ l_suffix.remove( l_suffix.size() - 1 ) ;
+
+ // Short loop on a match
+ if( hasEntry( l_suffix ) )
+ {
+ return l_suffix ;
+ }
+ }
+
+ // Should be the empty string distinguished name
+ return l_suffix ;
+ }
+
+
+ /**
+ * Gets the backend associated with a distinguished name if the name
+ * resolves to a suffix.
+ *
+ * @param a_dn the distinguished name to resolve to a backend
+ */
+ public AtomicBackend getBackend( Name a_dn )
+ throws NamingException
+ {
+ Name l_suffix = null ;
+ Iterator l_list = null ;
+ AtomicBackend l_backend = null ;
+
+ if( ! hasStarted() )
+ {
+ throw new IllegalStateException( "Module has not started!" ) ;
+ }
+
+ if( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug("" //ProtocolModule.getMessageKey()
+ + " - NexusModule.getBackend(): Request for DN " + a_dn) ;
+ }
+
+ // First lets just see if l_dn is a suffix to begin with using a cheap
+ // lookup in the normalized suffix String to backend Hash map.
+ if( m_backends.containsKey( a_dn.toString() ) )
+ {
+ BackendModule l_be =
+ ( BackendModule ) m_backends.get( a_dn.toString() ) ;
+
+ if( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug("" //ProtocolModule.getMessageKey()
+ + " - NexusModule.getBackend(): Request for DN " + a_dn
+ + " returning " + l_be.getImplementationName()
+ + " with suffix " + l_be.getSuffix() ) ;
+ }
+
+ return l_be ;
+ }
+
+ // So l_dn
+ l_list = listBackends() ;
+ while( l_list.hasNext() )
+ {
+ l_backend = ( AtomicBackend ) l_list.next() ;
+ l_suffix = l_backend.getSuffix() ;
+ if( a_dn.startsWith( l_suffix ) )
+ {
+ if( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug( "" //ProtocolModule.getMessageKey()
+ + " - NexusModule.getBackend(): returning backend "
+ + l_suffix ) ;
+ }
+ return l_backend ;
+ }
+ }
+
+ // After this point we are screwed!
+ if( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug( "Valid name " + a_dn + " not found under nexus "
+ + "backends. Throwing IllegalArgumentException!" ) ;
+ }
+
+ throw new IllegalArgumentException( a_dn + " not a valid namespace - "
+ + "could not find matching backend!" ) ;
+ }
+
+
+ public NameParser getNameParser()
+ {
+ return m_schema.getNameParser() ;
+ }
+
+
+ public NameParser getNormalizingParser()
+ {
+ return m_schema.getNormalizingParser() ;
+ }
+
+
+ public NameParser getNormalizingParser(Name a_name)
+ throws NamingException
+ {
+ Schema l_schema = this.getSchema(a_name) ;
+ if(l_schema != null) {
+ return l_schema.getNormalizingParser() ;
+ }
+
+ return null ;
+ }
+
+
+ /**
+ * JMX intended operation to list registered running backends this nexus
+ * currently has attacked to it.
+ *
+ * @phoenix:mx-operation
+ * @phoenix:mx-description Lists all atomic backends registered with the
+ * nexus (or system unified backend).
+ */
+ public String getRegisteredBackends()
+ {
+ StringBuffer l_buf = new StringBuffer() ;
+
+ l_buf.append("Nexus attached backend modules:").append("\n") ;
+ l_buf.append("=================================") ;
+ l_buf.append("=================================\n") ;
+ l_buf.append("\n\n") ;
+
+ Iterator l_list = listBackends() ;
+ while(l_list.hasNext()) {
+ BackendModule l_backend = (BackendModule) l_list.next() ;
+
+ l_buf.append("Implementation Name:\t") ;
+ l_buf.append(l_backend.getImplementationName()).append("\n") ;
+
+ l_buf.append("Implementation Class Name:\t") ;
+ l_buf.append(l_backend.getImplementationClassName()).append("\n") ;
+
+ l_buf.append("Suffix Serviced:\t") ;
+ l_buf.append(l_backend.getSuffix()).append("\n\n\n") ;
+ }
+
+ return l_buf.toString() ;
+ }
+
+
+ public Iterator listBackends()
+ {
+ return m_backends.values().iterator() ;
+ }
+
+
+ public Iterator listSuffixes()
+ {
+ return m_backends.keySet().iterator() ;
+ }
+
+
+ public void register( AtomicBackend a_backend )
+ {
+ // Dynamically register client manager with backends added on fly.
+ a_backend.registerClientManager( m_clientMan ) ;
+ m_backends.put( a_backend.getSuffix().toString(), a_backend ) ;
+ m_adminUsers.put( a_backend.getAdminUserDN().toString(), a_backend ) ;
+ }
+
+
+ public void unregister(AtomicBackend a_backend)
+ {
+ m_backends.remove(a_backend.getSuffix().toString()) ;
+ m_adminUsers.remove(a_backend.getAdminUserDN().toString()) ;
+ }
+
+
+ ///////////////////////////////////////
+ // Life-cycle Method Implementations //
+ ///////////////////////////////////////
+
+
+ /**
+ * We use this to get a handle on the schema manager.
+ *
+ * @phoenix:dependency name="org.apache.eve.schema.SchemaManager"
+ * @param a_manager the service manager that we get a BackendManager from
+ */
+ public void service(ServiceManager a_manager)
+ throws ServiceException
+ {
+ m_schemaMan =
+ (SchemaManager) a_manager.lookup(SchemaManager.ROLE) ;
+ m_schema = m_schemaMan.getCompleteSchema() ;
+ }
+
+
+ public void configure(Configuration a_config)
+ throws ConfigurationException
+ {
+ m_rootDSE = new RootDSE(m_schema) ;
+
+ try {
+ Configuration l_dseConfig = a_config.getChild(ROOTDSE_TAG, false) ;
+ if(l_dseConfig == null) {
+ String l_errmsg = "The " + ROOTDSE_TAG + " does not exist in "
+ + "the configuration section for the NexusModule. Cannot "
+ + "continue configuration without it!" ;
+ throw new ConfigurationException(l_errmsg) ;
+ }
+
+ Configuration [] l_attributes = l_dseConfig.getChildren(ATTRIBUTE_TAG) ;
+ for(int ii = 0 ; ii < l_attributes.length ; ii++ ) {
+ String l_name = l_attributes[ii].getAttribute("name", null) ;
+ String l_value = l_attributes[ii].getAttribute("value", null) ;
+ m_rootDSE.addValue(l_name, l_value) ;
+ }
+ } catch(Throwable e) {
+ String l_errmsg = "Encountered error while trying to construct the"
+ + " RootDSE during the NexusModule's configuration stage." ;
+ throw new ConfigurationException(l_errmsg, e) ;
+ }
+ }
+
+
+ public String getImplementationRole()
+ {
+ return ROLE ;
+ }
+
+
+ public String getImplementationName()
+ {
+ return "Unified Backend Nexus" ;
+ }
+
+
+ public String getImplementationClassName()
+ {
+ return this.getClass().getName() ;
+ }
+
+
+ public void registerClientManager(ClientManager a_manager)
+ {
+ m_clientMan = a_manager ;
+ }
+
+
+ public Schema getSchema(Name a_dn)
+ throws NamingException
+ {
+ BackendModule l_be = (BackendModule) getBackend(a_dn) ;
+ return l_be.getSchema() ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/NormalizerComponent.gif
==============================================================================
Binary file. No diff available.
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/ReadOnlyException.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/ReadOnlyException.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,35 @@
+/*
+ * $Id: ReadOnlyException.java,v 1.4 2003/07/29 22:08:02 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend ;
+
+
+import javax.naming.OperationNotSupportedException ;
+
+
+/**
+ * This exception is thrown when write operations are attempted against a
+ * Backend configured to be read-only.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.4 $
+ */
+public class ReadOnlyException
+ extends OperationNotSupportedException
+{
+ /**
+ * Constructs an Exception with a detailed message.
+ * @param a_message The message associated with the exception.
+ */
+ public ReadOnlyException(String a_message)
+ {
+ super(a_message) ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/RootDSE.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/RootDSE.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,414 @@
+/*
+ * $Id: RootDSE.java,v 1.3 2003/03/13 18:27:00 akarasulu Exp $
+ * $Prologue$
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend ;
+
+
+import java.util.Date ;
+import java.util.Collection ;
+
+import javax.naming.Name ;
+import javax.naming.NamingException ;
+import javax.naming.directory.AttributeInUseException ;
+import javax.naming.directory.InvalidAttributeValueException ;
+import javax.naming.directory.InvalidAttributeIdentifierException ;
+
+import org.apache.commons.collections.MultiHashMap ;
+
+import org.apache.ldap.common.name.LdapName ;
+import org.apache.eve.schema.Schema ;
+
+
+/**
+ * An entry implementation for the Berkeley backend.
+ *
+ * @task No schema checking going on right now - but this needs to change!
+ * @task Also we need to make sure that we are storing dates in the apropriate
+ * fashion
+ */
+public class RootDSE
+ extends MultiHashMap
+ implements LdapEntry
+{
+ private final Schema m_schema ;
+ private final Name m_dn = new LdapName() ;
+ private boolean m_isValid = false ;
+
+
+ RootDSE(Schema a_schema)
+ {
+ m_schema = a_schema ;
+ }
+
+
+ public Collection attributes()
+ {
+ return this.keySet() ;
+ }
+
+
+ public Schema getSchema()
+ {
+ return m_schema ;
+ }
+
+
+ public boolean equals(String a_dn)
+ throws NamingException
+ {
+ if(a_dn == null) {
+ return false ;
+ }
+
+ return a_dn.trim().equals("") ;
+ }
+
+
+ public boolean hasAttribute(String an_attributeName)
+ {
+ return containsKey(an_attributeName) ;
+ }
+
+
+ public boolean hasAttributeValuePair(String an_attribute, Object a_value)
+ {
+ if(containsKey(an_attribute)) {
+ Collection l_collection = getMultiValue(an_attribute) ;
+
+ if(null == l_collection && null == a_value) {
+ return true ;
+ } else if(null == l_collection || null == a_value) {
+ return false ;
+ } else if(l_collection.contains(a_value)) {
+ return true ;
+ } else {
+ return false ;
+ }
+ } else {
+ return false ;
+ }
+ }
+
+
+ /**
+ * Gets this entry's creation timestamp as a Date.
+ *
+ * @return Date representing the creation timestamp of this entry.
+ */
+ public Date getCreateTimestamp()
+ {
+ return new Date((String) getSingleValue(CREATETIMESTAMP_ATTR)) ;
+ }
+
+
+ /**
+ * Gets the distinguished name of the creator of this entry.
+ *
+ * The distinguished name is presumed to be normalized by the server naming
+ * subsystem in accordance with schema attribute syntax and attribute
+ * matching rules. The DN is also presumed to be syntacticly correct and
+ * within the namespace of this directory information base from which this
+ * Entry originated.
+ *
+ * @return the distinguished name of the creator.
+ */
+ public String getCreatorsName()
+ {
+ return (String) getSingleValue(CREATORSNAME_ATTR) ;
+ }
+
+
+ /**
+ * Gets the unique distinguished name associated with this entry as it was
+ * supplied during creation without whitespace trimming or character case
+ * conversions. This version of the DN is kept within the body of this
+ * Entry as an operational attribute so that it could be returned as it was
+ * given to the server w/o normalization effects: case and whitespace will
+ * be entact.
+ *
+ * @return the distinguished name of this entry as a String.
+ */
+ public String getEntryDN()
+ {
+ return (String) getSingleValue(DN_ATTR) ;
+ }
+
+
+ /**
+ * Gets the distinguished name of the last modifier of this entry.
+ *
+ * The distinguished name is presumed to be normalized by the server naming
+ * subsystem in accordance with schema attribute syntax and attribute
+ * matching rules. The DN is also presumed to be syntacticly correct and
+ * within the namespace of this directory information base from which this
+ * Entry originated.
+ *
+ * @return the DN of the user to modify this entry last.
+ */
+ public String getModifiersName()
+ {
+ return (String) getSingleValue(MODIFIERSNAME_ATTR) ;
+ }
+
+
+ /**
+ * Gets this entry's modification timestamp as a Date.
+ *
+ * @return Date representing the timestamp this entry was last modified.
+ */
+ public Date getModifyTimestamp()
+ {
+ return new Date((String)
+ getSingleValue(MODIFYTIMESTAMP_ATTR)) ;
+ }
+
+
+ /**
+ * Gets the normalized unique distinguished name associated with this
+ * entry. This DN unlike the user specified DN accessed via getDN() is not
+ * an operational attribute composing the body of this Entry.
+ *
+ * The distinguished name is presumed to be normalized by the server naming
+ * subsystem in accordance with schema attribute syntax and attribute
+ * matching rules. The DN is also presumed to be syntacticly correct and
+ * within the namespace of this directory information base from which this
+ * Entry originated.
+ *
+ * @return the normalized distinguished name of this entry as a String.
+ */
+ public Name getNormalizedDN()
+ throws NamingException
+ {
+ return m_dn ;
+ }
+
+
+ public Name getUnNormalizedDN()
+ throws NamingException
+ {
+ return m_dn ;
+ }
+
+
+ /**
+ * Gets the normalized unique distinguished name of this Entry's parent.
+ *
+ * The distinguished name is presumed to be normalized by the server naming
+ * subsystem in accordance with schema attribute syntax and attribute
+ * matching rules. The DN is also presumed to be syntacticly correct and
+ * within the namespace of this directory information base from which this
+ * Entry originated.
+ *
+ * @return the normalized distinguished name of this Entry's parent.
+ */
+ public String getParentDN()
+ {
+ return (String) getSingleValue(PARENTDN_ATTR) ;
+ }
+
+
+ /**
+ * Gets the distinguished name of the subschema subentry for this Entry.
+ *
+ * The distinguished name is presumed to be normalized by the server naming
+ * subsystem in accordance with schema attribute syntax and attribute
+ * matching rules. The DN is also presumed to be syntacticly correct and
+ * within the namespace of this directory information base from which this
+ * Entry originated.
+ *
+ * @return String of the subschema subentry distinguished name.
+ */
+ public String getSubschemaSubentryDN()
+ {
+ return (String) getSingleValue(SUBSCHEMASUBENTRY_ATTR) ;
+ }
+
+
+ /**
+ * Checks whether or not this Entry is a valid entry residing within a
+ * backend. Entries are validated on successful create() calls. When
+ * Entry instances are initialized in the java sense via the newEntry()
+ * call on backends, they are in the invalid state.
+ *
+ * @return true if this entry has been persisted to a backend,
+ * false otherwise.
+ */
+ public boolean isValid()
+ {
+ return m_isValid ;
+ }
+
+
+ /**
+ * Gets a multivalued attribute by name.
+ *
+ * @param an_attribName the name of the attribute to lookup.
+ * @return a Collection or null if no attribute value exists.
+ */
+ public Collection getMultiValue(String an_attribName)
+ {
+ return (Collection) get(an_attribName) ;
+ }
+
+
+ /**
+ * Gets a single valued attribute by name or returns the first value of a
+ * multivalued attribute.
+ *
+ * @param an_attribName the name of the attribute to lookup.
+ * @return an Object value which is either a String or byte [] or null if
+ * the attribute does not exist.
+ */
+ public Object getSingleValue(String an_attribName)
+ {
+ Collection l_col = (Collection) get(an_attribName) ;
+
+ if(null == l_col || l_col.isEmpty()) {
+ return null ;
+ }
+
+ return l_col.iterator().next() ;
+ }
+
+
+ /**
+ * Adds a value to this Entry potentially resulting in more than one value
+ * for the attribute/key.
+ *
+ * @param an_attribName attribute name/key
+ * @param a_value the value to add
+ * @throws InvalidAttributeIdentifierException when an attempt is made to
+ * add to or create an attribute with an invalid attribute identifier.
+ * @throws InvalidAttributeValueException when an attempt is made to add to
+ * an attribute a value that conflicts with the attribute's schema
+ * definition. This could happen, for example, if attempting to add an
+ * attribute with no value when the attribute is required to have at least
+ * one value, or if attempting to add more than one value to a single
+ * valued-attribute, or if attempting to add a value that conflicts with
+ * the syntax of the attribute.
+ */
+ public void addValue(String an_attribName, Object a_value)
+ throws
+ AttributeInUseException,
+ InvalidAttributeValueException,
+ InvalidAttributeIdentifierException
+ {
+ if(null == a_value || null == an_attribName) {
+ return ;
+ }
+
+ if(!m_schema.hasAttribute(an_attribName)) {
+ throw new InvalidAttributeIdentifierException(an_attribName +
+ " is not a valid schema recognized attribute name.") ;
+ }
+
+ if(containsKey(an_attribName) &&
+ m_schema.isSingleValue(an_attribName))
+ {
+ throw new AttributeInUseException("A key for attribute "
+ + an_attribName + " already exists!") ;
+ }
+
+
+ String l_value = null ;
+
+ if(a_value.getClass().isArray()) {
+ l_value = new String((byte []) a_value) ;
+ } else {
+ l_value = (String) a_value ;
+ }
+
+ if(l_value.trim().equals("")) {
+ return ;
+ }
+
+ if(!m_schema.isValidSyntax(an_attribName, l_value)) {
+ throw new InvalidAttributeValueException("'" + l_value
+ + "' does not comply with the syntax for attribute "
+ + an_attribName) ;
+ }
+
+ put(an_attribName, l_value) ;
+ }
+
+
+ /**
+ * Removes the attribute/value pair in this Entry only without affecting
+ * other values that the attribute may have.
+ *
+ * @param an_attribName attribute name/key
+ * @param a_value the value to remove
+ * @throws InvalidAttributeIdentifierException when an attempt is made to modify
+ * an attribute, its identifier, or its values that conflicts with the
+ * attribute's (schema) definition or the attribute's state. Also thrown
+ * if the specified attribute name does not exist as a key in this Entry.
+ */
+ public void removeValue(String an_attribName, Object a_value)
+ throws InvalidAttributeIdentifierException
+ {
+ if(!m_schema.hasAttribute(an_attribName)) {
+ throw new InvalidAttributeIdentifierException(an_attribName +
+ " is not a valid schema recognized attribute name.") ;
+ }
+
+ remove(an_attribName, a_value) ;
+ }
+
+
+ /**
+ * Removes all the attribute/value pairs in this Entry associated with the
+ * attribute.
+ *
+ * @param an_attribName attribute name/key
+ * @param an_attribName the value to remove
+ * @throws InvalidAttributeIdentifierException when an attempt is made to modify
+ * an attribute, its identifier, or its values that conflicts with the
+ * attribute's (schema) definition or the attribute's state. Also thrown
+ * if the specified attribute name does not exist as a key in this Entry.
+ */
+ public void removeValues(String an_attribName)
+ throws InvalidAttributeIdentifierException
+ {
+ if(!m_schema.hasAttribute(an_attribName)) {
+ throw new InvalidAttributeIdentifierException(an_attribName +
+ " is not a valid schema recognized attribute name.") ;
+ }
+
+ if(!containsKey(an_attribName)) {
+ return ;
+ }
+
+ remove(an_attribName) ;
+ }
+
+
+ /**
+ * Removes the specified set of attribute/value pairs in this Entry.
+ *
+ * @param an_attribName attribute name/key
+ * @param a_valueArray the set of values to remove
+ * @throws InvalidAttributeIdentifierException when an attempt is made to modify
+ * an attribute, its identifier, or its values that conflicts with the
+ * attribute's (schema) definition or the attribute's state. Also thrown
+ * if the specified attribute name does not exist as a key in this Entry.
+ */
+ public void removeValues(String an_attribName, Object [] a_valueArray)
+ throws InvalidAttributeIdentifierException
+ {
+ if(!m_schema.hasAttribute(an_attribName)) {
+ throw new InvalidAttributeIdentifierException(an_attribName +
+ " is not a valid schema recognized attribute name.") ;
+ }
+
+ for(int ii = 0; ii < a_valueArray.length; ii++) {
+ remove(an_attribName, a_valueArray[ii]) ;
+ }
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/SingletonCursor.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/SingletonCursor.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,55 @@
+/*
+ * $Id: SingletonCursor.java,v 1.2 2003/03/13 18:27:01 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend ;
+
+
+import java.util.NoSuchElementException ;
+
+
+/**
+ * An cursor that returns only one element! Used as annon inner class in so
+ * many places I had to create this one as well.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.2 $
+ */
+public class SingletonCursor
+ extends Cursor
+{
+ private final Object m_singleton ;
+
+ public SingletonCursor(Object a_singleton)
+ {
+ m_singleton = a_singleton ;
+ }
+
+ /**
+ * Throws NoSuchElementException all the time.
+ */
+ public Object advance()
+ {
+ try { close() ; } catch(Exception e) {}
+ return m_singleton ;
+ }
+
+ /**
+ * Always returns false.
+ */
+ public boolean canAdvance()
+ {
+ return !isClosed() ;
+ }
+
+ /**
+ * Does nothing.
+ */
+ public void freeResources() { }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/UnifiedBackend.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/UnifiedBackend.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,126 @@
+/*
+ * $Id: UnifiedBackend.java,v 1.13 2003/08/22 21:15:54 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend ;
+
+
+import java.util.Iterator ;
+
+import javax.naming.Name ;
+import javax.naming.NameParser ;
+import javax.naming.NamingException ;
+import javax.naming.InvalidNameException ;
+import javax.naming.NameNotFoundException ;
+import javax.naming.ldap.LdapContext ;
+
+import org.apache.eve.schema.Schema ;
+
+
+/**
+ * Represents a composite backend nexus that forwards backend requests to the
+ * apropriate Backends registered with it. UnifiedBackends are used to
+ * implement a name switch to get to the respective backend if one exists.
+ *
+ * Effectively, the Unified backend is a specific router interface in a system
+ * implementing the Router, (a.k.a. Request Router or Multiplexer) design
+ * pattern. AtomicBackends are the channels which are added and removed using
+ * the register and unregister methods of the UnifiedBackend. The routed
+ * messages are AtomicBackend interface calls.
+ */
+public interface UnifiedBackend
+ extends Backend
+{
+ /**
+ * Role of this service interface as mandated by the avalon framework.
+ */
+ public static final String ROLE = UnifiedBackend.class.getName() ;
+
+
+ /**
+ * Get's a Backend module by checking to see if a distinguished name
+ * contains the suffix of a backend as a prefix. If no backend can be
+ * found for a valid DN an IllegalArgumentException is thrown or an
+ * InvalidNameException is thrown if the DN is not syntactically correct.
+ *
+ * @param a_dn the distinguished name potentially contained by the backend.
+ * @return the Backend that would contain the entry if it were to exist.
+ * @throws InvalidNameException if a_dn is syntactically incorrect.
+ * @throws NameNotFoundException if no backend can house the
+ * hypothetical entry - it is not within the namespace of the federated
+ * backends.
+ * @deprecated we would like to deprecate this method because we would no
+ * longer like to expose it to the outside world which could misuse it
+ * without providing the required dn in normalized form.
+ */
+ AtomicBackend getBackend(Name a_dn)
+ throws NamingException ;
+
+
+ /**
+ * Gets the most significant Dn that exists within the server and hence can
+ * be matched to an actual entry.
+ *
+ * @param a_dn to use for the matching test.
+ * @return the matching portion of a_dn, or the valid empty string dn if no
+ * match was found.
+ */
+ Name getMatchedDn( Name a_dn )
+ throws NamingException, BackendException ;
+
+ /**
+ * Gets an iteration over the Backends managed by this BackendManager.
+ *
+ * @return the iteration over Backend instances.
+ */
+ Iterator listBackends() ;
+
+ /**
+ * Gets an iteration over the suffixes of the Backends managed by this
+ * UnifiedBackend.
+ *
+ * @return the iteration over Backend suffix names as Strings.
+ */
+ Iterator listSuffixes() ;
+
+ Schema getSchema(Name a_dn)
+ throws NamingException ;
+
+ NameParser getNormalizingParser() ;
+
+ NameParser getNameParser() ;
+
+ NameParser getNormalizingParser(Name a_dn)
+ throws NamingException ;
+
+ Name getNormalizedName(String a_name)
+ throws NamingException ;
+
+ Name getName(String a_name)
+ throws NamingException ;
+
+ RootDSE getRootDSE() ;
+
+ /**
+ * Registers a Backend with this BackendManager. Called for each Backend
+ * implementation after it is started. This is the only way it will receive
+ * requests from the protocol server.
+ *
+ * @param a_backend Backend component to register with this manager.
+ */
+ void register(AtomicBackend a_backend) ;
+
+ /**
+ * Unregisters a Backend with this BackendManager. Called for each
+ * registered Backend right befor it is to be stopped. This prevents
+ * protocol server requests from reaching the Backend.
+ *
+ * @param a_backend Backend component to unregister with this manager.
+ */
+ void unregister(AtomicBackend a_backend) ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/backendhowto.html
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/backendhowto.html Thu Jun 24 00:06:35 2004
@@ -0,0 +1,10 @@
+<html>
+<head>
+<title>Backend HOWTO</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF" text="#000000">
+Work in progress . . .
+</body>
+</html>
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/contract.html
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/contract.html Thu Jun 24 00:06:35 2004
@@ -0,0 +1,237 @@
+<html>
+<head>
+<title>Server Backend Contract</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF" text="#000000">
+<p><font color="#999999">$Id: contract.html,v 1.1.1.1 2002/11/13 23:46:12 akarasulu Exp $</font> </p>
+<h2 align="center">Server Backend Contract</h2>
+<p>The Server Backend Contract is defined syntactically by the APIs presented
+ in the backend package. Semantic contracts are also required to make sure that
+ Backends operate as expected and as efficiently as possible.</p>
+<p> </p>
+<h3 align="center">Syntax Overview</h3>
+<p>Backends are interfaces to an entry backing store. Backends provide create,
+ read, update and delete (CRUD) operations, against the store. Bulk retreivals
+ using filtered searches and heirarchical (parent child) relationships must also
+ be provided. </p>
+<p>Backends are the factories for BackendArtifacts. Together, the Backend interface
+ and these artifacts specify how entries and their attributes are accessed, created
+ and modified both individually and in bulk.</p>
+<p> </p>
+<h4>CRUD & Entry Life-Cycle Operations</h4>
+<p>The operations used to manipulate entries use the <b>CRUD</b> model which dictates
+ the Entry life-cycle. These Backend interface methods are straight forward:</p>
+<ul>
+ <li><code>newEntry(String a_dn):Entry</code></li>
+ <li><font color="#FF0000"><code><b><u>c</u></b></code></font><code>reate(Entry
+ an_entry):void</code></li>
+ <li><code><b><u><font color="#FF0000">r</font></u></b>ead(String a_dn):Entry</code></li>
+ <li><code><b><u><font color="#FF0000">u</font></u></b>pdate(Entry an_entry):void</code></li>
+ <li><code><b><u><font color="#FF0000">d</font></u></b>elete(Entry an_entry):void</code></li>
+</ul>
+<p>Perhaps the only method worthy of explanation is <code>newEntry</code>. This
+ method constructs a new empty and invalid Entry instance. Valid entries exist
+ within the Backend's backing store and invalid entries do not: they have been
+ instantiated yet <code>create</code> has not been called on the Entry. Backends
+ are Entry factories in this respect. An invalid Entry merely contains the user
+ provide DN string as an operational attribute and the <a href="dnnormalization.html">normalized</a>
+ string stored as a property of the class. These <b>CRUD</b> methods do the obvious
+ once the ball is set in motion. Newly instantiated entries are altered via Entry
+ interface methods and added to the Backend using the <code>create</code> method.
+ Once created the Entry can have attributes manipulated and can be used to make
+ successful calls to <code>delete</code>, and <code>update</code> (presuming
+ schema constraints are not violated). Calls to <code>read</code> will return
+ created and updated entries. These interfaces are simple and straight forward.
+ The rest of the Backend interface methods can be categorized as non-<b>CRUD</b>
+ methods belonging to the set of entry checker methods, hierarchical operations,
+ or search operations:</p>
+<p>Entry Test Methods:</p>
+<ul>
+ <li><code>hasEntry(String a_dn):boolean</code></li>
+ <li><code>isSuffix(Entry an_entry):boolean</code></li>
+</ul>
+<p>Hierarchical Operations:</p>
+<ul>
+ <li><code>getParent(String a_childDN):Entry</code></li>
+ <li><code>listChildren(String a_parentDN):Cursor</code></li>
+</ul>
+<p>Search Operations:</p>
+<ul>
+ <li><code>search(String a_base, String a_filter, SearchControls a_ctls):Cursor</code></li>
+</ul>
+<p>The Backend is responsible for enforcing Schema constraints. Separate Schema
+ interfaces dictate the interaction between Backend and Schema subsystems. Hence
+ schema based attribute normalization and schema based objectclass constraint
+ checking are delegated to the Schema subsystem by the Backend. This dependency
+ is the source of the various kinds of NamingExceptions thrown by most of the
+ methods on the Backend interface. A Backend simply let's these exceptions pass
+ through.</p>
+<p> </p>
+<h4>BackendArtifacts: Helper Interfaces</h4>
+<p>An Entry is a pivotal helper class and a Backend artifact. It represents a
+ server side LDAP entry by containing attributes. It is the atomic unit of storage
+ within a Backend. In this respect an Entry is a value object. Once instantiated
+ by a Backend using the <code>newEntry</code> call, attribute value pair add
+ methods are used to add single and multivalued attributes to new instances.
+ Once all attributes are added the Entry can be stored in the Backend via <code>create</code>.
+ Change and remove mutators are used afterwords on the validated Entry to alter
+ its attributes. An Entry can be repeatedly updated this way until it is deleted.
+ Backends and cursors provide the means to access and store entries while entries
+ provide the means to alter attributes.</p>
+<p>Cursor artifacts extend the Backend interfaces to provide search and bulk access
+ methods to efficiently iterate over entries. In very large DIBs entries cannot
+ be loaded on mass due to resource limitations. Likewise search implementations
+ must manage joins efficiently avoiding mass retreivals or table scans returning
+ results on an as needed basis. Cursor are the iterative conduit into the DIB.</p>
+<p>The Cursor class is abstract and implemented as a NamingEnumeration that extends
+ the Observable class. Cursors will interface with the Backend factory that created
+ it. Most interfaces on Backends could potentially throw various subclasses of
+ NamingException. It was natural to encapsulate all possible naming exceptions
+ by implementing a NamingEnumeration. Observable was extended to potentially
+ anounce open/close state changes to managing Backends so resouces associated
+ with Cursors can be freed. The Backend interface does not extend Observable
+ however. Not all backends will need to 'observe' these state changes. Implementations
+ may decide to complement Cursor Observables by implementing the Observer interface,
+ the potential is there if its use is needed. Also subtype interfaces of Backend,
+ namely Atomic Backend and Unified Backend are designed to be used as service
+ interfaces in the avalon framework. The design pattern could be compromised
+ if the Observer's update method were to be exposed as a service interface.</p>
+<p>The abstract Cursor class declares the NamingException methods final and introduces
+ the abstract protected advance, canAdvance, and freeResources methods requiring
+ their implementation by concrete Cursors. These seals were introduced to allow
+ the abstract Cursor class to automatically close itself without the chance of
+ tampering by subclasses. When exhausted or when exceptions prevent further iteration,
+ Cursors call close. Enumeration and NamingEnumeration semantics are maintained
+ by wraping unexpected Backend exceptions in a subtype of NoSuchElement exception
+ called CursorException. The JDK expects such an exception to be thrown when
+ nextElement and next are called on exhausted instances of these interfaces.</p>
+<p> </p>
+<h3 align="center">Server Backend Semantics</h3>
+<p>Some operational semantics are supported by the syntax of classes and interfaces
+ defined in the backend package. Others are not and need to be explicitly defined
+ here. Exception handling semantics and iterative cursor behavoir are aspects
+ of expected semantics in the server backend contract.</p>
+<p> </p>
+<h4>Exception Handling</h4>
+<p>To allow the gambit of Backend implementations, while balancing complexity
+ with performance we quickly realized that most effective Backends must interface
+ with a Schema subsystem. Attribute value and DN normalization will be a concern
+ for every Backend. This is unavoidable. Attribute value normalization is specific
+ to the type of the attribute and hence is dependent upon schema information.</p>
+<p>Value normalization requires valid values and introduces schema checking issues:
+ object class correctness, attribute syntax correctness, attribute value syntaxes
+ and matching rules. There simply is no way to avoid these aspects however they
+ can and will be encapsulated within schema subsystem components provided to
+ all backends as an independent service. Backends interface with the schema subsystem
+ through Schemas and attribute Normalizer interfaces to conduct schema checking
+ and validation. These interfaces will throw NamingException subclasses to announce
+ schema violations. Backends need to remain as simple as possible. Minimizing
+ the amount of exception handling within backends to manage calls to Schema and
+ Normalizer interfaces keeps the complexity down. For these reasons many methods
+ on backend package classes and interfaces throw subclasses of NamingExceptions.
+ Hence Backends and their artifacts pass through exceptions generated by schema
+ method calls. </p>
+<p>Backend implementations need not handle NamingExceptions generated by calls
+ to dependent schema APIs. All Backends hence will need to have access to the
+ schema subsystem. The backend package does not define how this actually happens
+ nor does it place any restriction on the means. This is due to the use of various
+ server composition schemes: embedded, standalone and micro-kernel configurations.
+ Handling naming subsystem, schema subsystem and BackendException failures are
+ the responsibility of protocol processing elements which sit above these modules
+ in their various configurations.</p>
+<p>Exception bubble up from schema subsystem calls. The types of exceptions generated
+ by the various interfaces hint at what they do. We have tried to distribute
+ the number of exception types thrown by interfaces based on aspect. Some naming
+ exceptions will result when validating the correctness of attribute values using
+ attribute syntaxes and their identifiers. Others result in Entry level schema
+ violations where the required attributes in an objectclass definition as missing
+ or extra attributes not allowed by the schema have been added. We will coin
+ the phrase entry level and attribute level to describe the two diffent types
+ of violations we must manage. The Backend interface must manage entry level
+ violations first because it is the facade through which all entries are created,
+ updated and deleted. Secondly, restrictions on entry attribute composition cannot
+ be managed by an Entry. Think about what would happend as an entry is being
+ built. Stages in building it would of course be inconsistent with schema requirements
+ on objectclasses. When an objectclass attribute is added the Entry is already
+ inconsistent if that objectclass has manditory attribute requirements. What
+ do you add first the objectclass attribute or the attributes it requires to
+ be consistent with the objectclass definition? If the attributes required are
+ added first they violate the schema by not having the appropriate objectclass
+ attribute. To avoid this chicken or egg problem such Entry level schema checking
+ is delegated to the Backend interfaces and avoided by Entry interfaces. Hence
+ the contract presumes that Backend implementations manage objectclass schema
+ checks while Entry implementations for that Backend manage attribute schema
+ checks. </p>
+<p>Other non-schema subsystem associated exceptions (also NamingException subclasses)
+ are thrown by the search method. These exceptions express problems with search
+ criteria. Cursors created by searches can also throw other exceptions associated
+ with resources or search limitations. These matters are left to the discretion
+ of the backend implementors. Below we categorically list some of the exceptions
+ that could be thrown by backend implementation classes which have conveniently
+ been defined for us by the JNDI packages. Note that some exceptions in JNDI
+ were defined specifically to express client side or client side provider errors.
+ If we elect to use them we refer to them in our own serverside context.</p>
+<p><b>Cursor: </b></p>
+<p>Search errors (implicitly defined as NamingExceptions)</p>
+<ul>
+ <li>CannotProceedException</li>
+ <li>InterruptedNamingException</li>
+ <li>LimitExceededException</li>
+ <li>LinkException</li>
+ <li>LinkLoopException</li>
+ <li>MalformedLinkException</li>
+ <li>PartialResultException</li>
+ <li>SizeLimitExceededException</li>
+ <li>TimeLimitExceededException</li>
+</ul>
+<h4>Backend: </h4>
+<p> Objectclass level schema violations (explicitly thrown)</p>
+<ul>
+ <li>NameNotFoundException</li>
+ <li>InvalidNameException</li>
+ <li>NameAlreadyBoundException</li>
+ <li>ContextNotEmptyException</li>
+ <li>InvalidSearchFilterException</li>
+ <li>InvalidSearchControlsException</li>
+ <li>InvalidAttributesException</li>
+ <li>SchemaViolationException<br>
+ </li>
+</ul>
+<h4>Entry: </h4>
+Attribute level schema violations (explicitly thrown)
+<ul>
+ <li>AttributeModificationException</li>
+ <li>InvalidAttributeValueException</li>
+ <li>InvalidAttributeIdentifierException</li>
+</ul>
+<p> </p>
+<h4>Cursor Behavoir</h4>
+<p>Cursors react to exceptional conditions based on the iteration methods used.
+ If Cursors are used as Enumerations callers are sheilded from exception handling.
+ Both backend and naming exceptions are logged and the Cursor is automatically
+ closed if the hasNextElement method bombs. The nextElement method logs then
+ transduces NamingExceptions and BackendExceptions into a CursorException which
+ is a subclass of NoSuchElementException. Implementations must support the Enumeration
+ contract by making sure that calls to nextElement preceded by hasNextElement
+ call with a true return value never throw a CursorException. This can be accomplished
+ by prefetching values.</p>
+<p>A similar contract is required for NamingEnumeration interfaces. The hasNext
+ method sheilds callers from handling Backend exceptions while allowing them
+ to handle NamingExceptions. BackendExceptions when encountered are logged and
+ the Cursor is closed. Likewise the next method allows callers to handle NamingExceptions,
+ yet sheilds them from BackendExceptions resulting from delegated calls to advance.
+ It logs the BackendException and rethrows it as a CursorException. Again NamingEnumeration
+ semantics must be adhered to. Calls to next should not throw a CursorException
+ if hasNext returned true before the call. Prefetching again is the key.</p>
+<p>Concrete Cursor implementors may wonder how they can comply with the Enumeration
+ and NamingEnumeration contract if all their interface methods are made final
+ by the abstract Cursor class. Again prefetching is the key! Cursor implementors
+ should prefetch at Cursor initialization. If the prefetch fails the BackendException
+ can be handled by the caller to the Backend interface method instantiating the
+ Cursor. If the prefetch yeilds no result a closed exhausted Cursor is returned.
+ They are empty in such cases and the contract is satisfied.</p>
+<p> </p>
+</body>
+</html>
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/dnnormalization.html
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/dnnormalization.html Thu Jun 24 00:06:35 2004
@@ -0,0 +1,63 @@
+<html>
+<head>
+<title>LDAP & X.500 Distinguished Name Normalization</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF" text="#000000">
+<p><font color="#999999">$Id: dnnormalization.html,v 1.1.1.1 2002/11/13 23:46:12 akarasulu Exp $</font></p>
+<h2 align="center">LDAP & X.500 Distinguished Name Normalization</h2>
+
+<p>Distinguished names as specified by <a href="http://www.ietf.org/rfc/rfc2253.txt">RFC
+ 2253</a> or <a href="http://www.ietf.org/rfc/rfc1779.txt">RFC 1779</a> (obsoleted
+ by 2253) should be normalized for Backend storage when used as keys. Without
+ normalization equality matching against inconsistant user formated strings will
+ fail miserably. Several articals and forums have debated how the normalization
+ should proceed. In the 1.4 JDK a new X500Principal class handles normalization
+ of distinguished names from a String representation and an BER encoder ASN.1
+ representation. SUN describes it better than I can in the Javadocs for <a href="http://java.sun.com/j2se/1.4/docs/api/javax/security/auth/x500/X500Principal.html#getName(java.lang.String)">X500Principal</a>.
+</p>
+<p>The Naming subsystem of our server shall use such a class or define it's own
+ canonicalization of the distinguished name. The best bet is to use X500Principal
+ yet there might be an advantage to making this aspect a pluggable feature since
+ many ways exist and arguments over the matter are still unsettled.</p>
+<p>Regardless of the means used to generate DN keys (normalized DNs) the original
+ user provided formating of the DN at creation or modification time shall be
+ preserved under the Entry's attributes or its operational attributes depending
+ on what DN we are refering to. So when we return the entry to the user it is
+ formatted exactly in the way the user provided the DN in the first place. Some
+ operational DN attributes managed by either the Backend or the naming subsystem
+ of the server will be kept in normalized form.</p>
+<p>Backends receive entries for creation starting with the suffix or root Entry
+ of their Directory Information Base (DIB). Operational keyed DNs must be provided
+ in normalized and user provided formats. Other non-operational or administrative
+ attributes may need normalization based on their specific attribute syntax if
+ they are indexed: presuming the backend manages indices. The Backend must interface
+ with both the schema subsystem and an attribute syntax specific normalizer to
+ generate the appropriate normalized keys in canonical form for these attribute
+ indices.</p>
+<p>Matching rules, attribute syntax, and attribute type information is required
+ to correctly normalize attributes. For example case sensitive strings can not
+ be case normalized (i.e. all lower cased) for use as keys. If case sensitive
+ strings are case normalized we would not be able to store things like Unix file
+ names: Notes.txt and notes.txt could not exist as separate files within a common
+ directory. Because schema information is required to format/normalize/canonicalize
+ attribute values for key representation the normalization functionality should
+ be provided by either the Schema subsystem or by a Normalizer component that
+ is dependent on the Schema subsystem or rather generated/provided by it. Figure
+ 1 shows how the intramodule dependencies would look:</p>
+<p><img src="NormalizerComponent.gif" width="601" height="168"></p>
+<p>The Backend subsystems would be dependent on components and interfaces within
+ the schema subsystem. Normalizers will obviously be dependent on the nature
+ of the attribute so the SchemaModule would provide access to one based on an
+ attribute type via the Schema interface. A Backend would be provided a handle
+ to the Schema subsystem by the server at some point in the module's lifecycle.
+ The Backend in it's solid state would ask the SchemaModule for its Schema using
+ its suffix as a parameter. The module would return the appropriate schema for
+ that Backend. The Backend would then proceed to ask the Schema for an attribute
+ specific Normalizer by providing the name of the attribute as a parameter to
+ a getNormalizer method on the Schema interface. The Normalizer would then be
+ used to generate a normalized attribute value from the user provided attribute
+ value which can now be used by the Backend as a key.</p>
+</body>
+</html>
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/Database.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/Database.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,233 @@
+/*
+ * $Id: Database.java,v 1.4 2003/03/13 18:27:14 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm ;
+
+
+import javax.naming.Name ;
+import java.util.Iterator ;
+import java.math.BigInteger ;
+import javax.naming.NamingException ;
+
+import org.apache.eve.schema.Schema ;
+import org.apache.eve.backend.BackendException ;
+
+import org.apache.eve.backend.jdbm.index.Index ;
+import org.apache.eve.backend.jdbm.index.IndexCursor;
+import org.apache.eve.backend.Cursor ;
+
+import org.apache.regexp.RE ;
+import org.apache.commons.collections.MultiMap ;
+import org.apache.avalon.framework.logger.Logger;
+
+
+/**
+ *
+ */
+public interface Database
+{
+ public Schema getSchema() ;
+
+ //////////////////////
+ // Index Operations //
+ //////////////////////
+
+ public void addIndexOn(String an_attribute)
+ throws BackendException, NamingException ;
+
+ public boolean hasIndexOn(String an_attribute) ;
+
+ public Index getIndex(String an_attribute)
+ throws IndexNotFoundException ;
+
+ public BigInteger getEntryId(String a_dn)
+ throws BackendException, NamingException ;
+
+ public String getEntryDn(BigInteger a_id)
+ throws BackendException ;
+
+ public BigInteger getParentId(String a_dn)
+ throws BackendException, NamingException ;
+
+ public BigInteger getParentId(BigInteger a_childId)
+ throws BackendException ;
+
+ public int count()
+ throws BackendException ;
+
+ public int getIndexScanCount(String an_attribute)
+ throws BackendException, NamingException ;
+
+ public int getIndexScanCount(String an_attribute, String a_value)
+ throws BackendException, NamingException ;
+
+ public int getIndexScanCount(String an_attribute, String a_value,
+ boolean isGreaterThan)
+ throws BackendException, NamingException ;
+
+ public boolean assertIndexValue(String an_attribute, Object a_value,
+ BigInteger a_id)
+ throws BackendException, NamingException ;
+
+ public boolean assertIndexValue(String an_attribute, Object a_value,
+ BigInteger a_id, boolean isGreaterThan)
+ throws BackendException, NamingException ;
+
+ public IndexCursor getIndexCursor(String an_attribute)
+ throws BackendException, NamingException ;
+
+ public IndexCursor getIndexCursor(String an_attribute, String a_value)
+ throws BackendException, NamingException ;
+
+ public IndexCursor getIndexCursor(String an_attribute, String a_value,
+ boolean isGreaterThan)
+ throws BackendException, NamingException ;
+
+ public IndexCursor getIndexCursor(String an_attribute, RE a_regex)
+ throws BackendException, NamingException ;
+
+ public IndexCursor getIndexCursor(String an_attribute, RE a_regex,
+ String a_prefix)
+ throws BackendException, NamingException ;
+
+ //////////////////////////////////
+ // Master Table CRUD Operations //
+ //////////////////////////////////
+
+ public void create(LdapEntryImpl an_entry, BigInteger a_id)
+ throws BackendException, NamingException ;
+
+ public LdapEntryImpl read(BigInteger a_id)
+ throws BackendException, NamingException ;
+
+ public void update(LdapEntryImpl an_entry)
+ throws BackendException, NamingException ;
+
+ public void delete(BigInteger a_id)
+ throws BackendException, NamingException ;
+
+ /////////////////////////////
+ // Parent/Child Operations //
+ /////////////////////////////
+
+ public Cursor getChildren(BigInteger a_id)
+ throws BackendException, NamingException ;
+
+ public int getChildCount(BigInteger a_id)
+ throws BackendException, NamingException ;
+
+ public Name getSuffix() ;
+
+ public LdapEntryImpl getSuffixEntry()
+ throws BackendException, NamingException ;
+
+ public BigInteger getNextId()
+ throws BackendException ;
+
+ public BigInteger getCurrentId()
+ throws BackendException ;
+
+ public void sync() ;
+
+ public void close() ;
+
+ /////////////////////
+ // Utility Methods //
+ /////////////////////
+
+
+ public void setProperty(String a_propertyName, String a_propertyValue)
+ throws BackendException ;
+
+ public String getProperty(String a_propertyName)
+ throws BackendException ;
+
+ /**
+ * Lists only the User Defined Index (UDI) Attributes.
+ */
+ public Iterator getUDIAttributes() ;
+
+ public final static String [] SYS_INDICES =
+ { Schema.DN_ATTR, Schema.EXISTANCE_ATTR, Schema.HIERARCHY_ATTR} ;
+
+ /**
+ * Gets the names of the maditory system indices used by the database.
+ * These names are used as the [operational] 'attribute' or key names
+ * of the indices. All cursor operations and assertion operations use
+ * these names to select the appropriate UDI (User Defined Index) or SDI
+ * (System Defined Index) to operate upon.
+ */
+ public String [] getSystemIndices() ;
+
+ public MultiMap getIndices(BigInteger a_id)
+ throws BackendException, NamingException ;
+
+ /**
+ * Modifies the relative distinguished name (RDN) of an entry
+ * without changing any parent child relationships. This call
+ * has the side effect of altering the distinguished name of
+ * descendent entries if they exist. The boolean argument will
+ * optionally remove the existing RDN attribute value pair
+ * replacing it with the new RDN attribute value pair. If other
+ * RDN attribute value pairs exist besides the current RDN they
+ * will be spared.
+ *
+ * @param an_entry the entry whose RDN is to be modified.
+ * @param a_newRdn the new Rdn that is to replace the current Rdn.
+ * @param a_deleteOldRdn deletes the old Rdn attribute value pair if true.
+ * @throws BackendException when the operation cannot be performed due to a
+ * backing store error.
+ * @throws NamingException when naming violations and or schema violations
+ * occur due to attempting this operation.
+ */
+ public void modifyRdn(org.apache.eve.backend.jdbm.LdapEntryImpl an_entry,
+ String a_newRdn, boolean a_deleteOldRdn)
+ throws BackendException, NamingException ;
+
+ /**
+ * This overload combines the first two method operations into one.
+ * It changes the Rdn and the parent prefix at the same time while
+ * recursing name changes to all descendants of the child entry. It
+ * is obviously more complex than the other two operations alone and
+ * involves changes to both parent child indices and DN indices.
+ *
+ * @param a_parentEntry the parent the child is to subordinate to.
+ * @param a_childEntry the child to be moved under the parent.
+ * @param a_newRdn the new Rdn that is to replace the current Rdn.
+ * @param a_deleteOldRdn deletes the old Rdn attribute value pair if true.
+ * @throws BackendException when the operation cannot be performed due to a
+ * backing store error.
+ * @throws NamingException when naming violations and or schema violations
+ * occur due to attempting this operation.
+ */
+ public void move(LdapEntryImpl a_parentEntry, LdapEntryImpl a_childEntry,
+ String a_newRdn, boolean a_deleteOldRdn)
+ throws BackendException, NamingException ;
+
+ /**
+ * Moves a child entry without changing the RDN under a new parent
+ * entry. This effects the parent child relationship between the
+ * parent entry and the child entry. The index for the child
+ * mapping it to the current parent is destroyed and a new index
+ * mapping it to the new parent is created. As a side effect the
+ * name of the child entry and all its descendants will reflect the
+ * move within the DIT to a new parent. The old parent prefix to
+ * the distinguished names of the child and its descendents will be
+ * replaced by the new parent DN prefix.
+ *
+ * @param a_parentEntry the parent the child is to subordinate to.
+ * @param a_childEntry the child to be moved under the parent.
+ * @throws BackendException when the operation cannot be performed due to a
+ * backing store error.
+ * @throws NamingException when naming violations and or schema violations
+ * occur due to attempting this operation.
+ */
+ public void move(LdapEntryImpl a_parentEntry, LdapEntryImpl a_childEntry)
+ throws BackendException, NamingException ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/EntryCursor.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/EntryCursor.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,66 @@
+/*
+ * $Id: EntryCursor.java,v 1.3 2003/03/13 18:27:14 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm ;
+
+
+import org.apache.eve.backend.Cursor ;
+import org.apache.eve.backend.BackendException ;
+import org.apache.eve.backend.jdbm.index.IndexRecord ;
+
+import javax.naming.NamingException ;
+
+/**
+ * @testcase org.apache.eve.backend.jdbm.TestEntryCursor
+ */
+public class EntryCursor
+ extends Cursor
+{
+ protected final JdbmModule m_backend ;
+ protected final Cursor m_cursor ;
+
+ /**
+ * Creates a cursor over all the elements in the table. The key will change
+ * to represent the value of key pointed to by this cursor.
+ *
+ * @param a_table Db to iterate over.
+ * @throws DbException if something goes drastically wrong.
+ */
+ public EntryCursor(JdbmModule a_backend, Cursor a_cursor)
+ {
+ m_cursor = a_cursor ;
+ m_backend = a_backend ;
+ }
+
+
+ protected Object advance()
+ throws BackendException, NamingException
+ {
+ IndexRecord l_rec = (IndexRecord) m_cursor.next() ;
+ return m_backend.read(l_rec.getEntryId()) ;
+ }
+
+
+ protected boolean canAdvance()
+ throws BackendException, NamingException
+ {
+ return m_cursor.hasMore() ;
+ }
+
+
+ protected void freeResources()
+ {
+ try {
+ m_cursor.close() ;
+ } catch (Exception e) {
+ e.printStackTrace() ;
+ getLogger().error("While closing underlying IndexCursor: ", e) ;
+ }
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/IndexNotFoundException.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/IndexNotFoundException.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,63 @@
+/*
+ * $Id: IndexNotFoundException.java,v 1.2 2003/03/13 18:27:15 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm ;
+
+
+import org.apache.eve.backend.BackendException ;
+
+
+public class IndexNotFoundException
+ extends BackendException
+{
+ public final String m_indexName ;
+
+ /**
+ * Constructs an Exception with a detailed message.
+ * @param a_message The message associated with the exception.
+ */
+ public IndexNotFoundException(String a_indexName)
+ {
+ super("Cannot efficiently search the DIB w/o an index on attribute "
+ + a_indexName + "\n. To allow such searches please contact the "
+ + "directory\nadministrator to create the index or to enable "
+ + "referals on searches using these\nattributes to a replica with "
+ + "the required set of indices.") ;
+ m_indexName = a_indexName ;
+ }
+
+
+ /**
+ * Constructs an Exception with a detailed message.
+ * @param a_message The message associated with the exception.
+ */
+ public IndexNotFoundException(String a_message, String a_indexName)
+ {
+ super(a_message) ;
+ m_indexName = a_indexName ;
+ }
+
+
+ /**
+ * Constructs an Exception with a detailed message and an error.
+ * @param a_message The message associated with the exception.
+ */
+ public IndexNotFoundException(String a_message, String a_indexName,
+ Throwable a_throwable)
+ {
+ super(a_message, a_throwable) ;
+ m_indexName = a_indexName ;
+ }
+
+
+ public String getIndexName()
+ {
+ return m_indexName ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/JdbmDatabase.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/JdbmDatabase.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,1049 @@
+/*
+ * $Id: JdbmDatabase.java,v 1.12 2003/08/06 03:01:25 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm ;
+
+
+import java.util.Map ;
+import java.util.HashMap ;
+import java.util.Iterator ;
+import java.util.Collection ;
+
+import javax.naming.Name ;
+import javax.naming.NameParser ;
+import javax.naming.NamingException ;
+
+import java.io.File ;
+import java.io.IOException ;
+
+import java.math.BigInteger ;
+import java.text.ParseException ;
+
+import org.apache.eve.backend.Cursor ;
+import org.apache.eve.schema.Schema ;
+import org.apache.eve.schema.Normalizer ;
+import org.apache.eve.backend.LdapEntry ;
+import org.apache.eve.backend.BackendException ;
+import org.apache.eve.backend.jdbm.index.Index ;
+import org.apache.eve.backend.jdbm.index.JdbmIndex ;
+import org.apache.eve.backend.jdbm.index.IndexRecord ;
+import org.apache.eve.backend.jdbm.table.MasterTable ;
+import org.apache.eve.backend.jdbm.index.IndexCursor ;
+
+import org.apache.regexp.RE ;
+import org.apache.avalon.framework.ExceptionUtil ;
+import org.apache.avalon.framework.logger.Logger ;
+import org.apache.avalon.framework.logger.AbstractLogEnabled ;
+
+import org.apache.commons.collections.MultiMap ;
+import org.apache.commons.collections.MultiHashMap ;
+
+import org.apache.ldap.common.name.DnParser ;
+import org.apache.ldap.common.util.NamespaceTools ;
+
+import jdbm.recman.RecordManager ;
+
+
+/**
+ * No caching just coordinated maintance of indices on CRUD operations for
+ * LdapEntrys in a BerkeleyDatabase. This is not a module but a component
+ * used by the Berkeley Db Backend Module.
+ * @testcase <{TestDatabase}>
+ */
+public class JdbmDatabase
+ extends AbstractLogEnabled
+ implements Database
+{
+ public static boolean debug = true ;
+
+ public Logger log ;
+ private final RecordManager m_recMan ;
+ private final Name m_suffix ;
+ private final String m_wkdir ;
+ private final Schema m_schema ;
+ private final MasterTable m_master ;
+ private final JdbmIndex m_nameIdx ;
+ private final JdbmIndex m_existanceIdx ;
+ private final JdbmIndex m_hierarchyIdx ;
+ private final Map m_indices ;
+
+ private NameParser m_nonNormalizingParser = null ;
+ private final NameParser m_parser ;
+
+
+ public JdbmDatabase(final Schema a_schema,
+ final Name a_suffix,
+ final String a_wkdirPath)
+ throws BackendException, NamingException
+ {
+ m_schema = a_schema ;
+ m_suffix = a_suffix ;
+ m_wkdir = a_wkdirPath ;
+
+ m_parser = m_schema.getNormalizingParser() ;
+ try {
+ m_nonNormalizingParser = new DnParser() ;
+ } catch(IOException e) {
+ throw new BackendException("Could not initialize the non-" +
+ "normalizing DnParser", e) ;
+ }
+
+ try {
+ m_recMan = new RecordManager(a_wkdirPath
+ + File.separator + "master") ;
+ m_recMan.disableTransactions() ;
+ } catch(IOException e) {
+ String l_msg = "Could not initialize RecordManager:\n"
+ + ExceptionUtil.printStackTrace(e) ;
+ throw new BackendException(l_msg, e) ;
+ }
+
+ m_master = new MasterTable(m_recMan) ;
+ m_nameIdx = new JdbmIndex(Schema.DN_ATTR, m_schema, m_wkdir) ;
+ m_existanceIdx =
+ new JdbmIndex(Schema.EXISTANCE_ATTR, m_schema, m_wkdir) ;
+ m_hierarchyIdx =
+ new JdbmIndex(Schema.HIERARCHY_ATTR, m_schema, m_wkdir) ;
+ m_indices = new HashMap() ;
+ }
+
+
+ public Schema getSchema()
+ {
+ return m_schema ;
+ }
+
+
+ //////////////////////
+ // Index Operations //
+ //////////////////////
+
+
+ public void addIndexOn(String an_attribute)
+ throws BackendException, NamingException
+ {
+ an_attribute = an_attribute.toLowerCase() ;
+ if(m_schema.isBinary(an_attribute)) {
+ throw new BackendException(
+ "Indices not allowed on binary attributes!") ;
+ }
+
+ Normalizer l_normalizer = m_schema.getNormalizer(an_attribute, true) ;
+
+ if(null == l_normalizer) {
+ throw new BackendException("Cannot create index on attribute "
+ + an_attribute + " when schema does not have a normalizer for "
+ + "attribute " + an_attribute) ;
+
+ }
+
+ an_attribute = an_attribute.toLowerCase() ;
+ JdbmIndex l_index = new JdbmIndex(an_attribute, m_schema, m_wkdir) ;
+ l_index.enableLogging(super.getLogger()) ;
+ m_indices.put(an_attribute, l_index) ;
+ }
+
+
+ public boolean hasIndexOn(String an_attribute)
+ {
+ try {
+ Index l_index = getIndex(an_attribute) ;
+ return l_index != null ;
+ } catch(IndexNotFoundException e) {
+ return false ;
+ }
+ }
+
+
+ public Index getIndex(String an_attribute)
+ throws IndexNotFoundException
+ {
+ String l_lowerCased = an_attribute.toLowerCase() ;
+
+ if(m_indices.containsKey(an_attribute)) {
+ return (Index) m_indices.get(an_attribute) ;
+ } else if(m_indices.containsKey(l_lowerCased)) {
+ return (Index) m_indices.get(l_lowerCased) ;
+ } else if(an_attribute.equals(Schema.DN_ATTR)) {
+ return m_nameIdx ;
+ } else if(an_attribute.equals(Schema.EXISTANCE_ATTR)) {
+ return m_existanceIdx ;
+ } else if(an_attribute.equals(Schema.HIERARCHY_ATTR)) {
+ return m_hierarchyIdx ;
+ } else {
+ throw new IndexNotFoundException("An index on attribute " +
+ an_attribute + " does not exist!") ;
+ }
+ }
+
+
+ public BigInteger getEntryId(String a_dn)
+ throws BackendException, NamingException
+ {
+ return m_nameIdx.getForward(a_dn) ;
+ }
+
+
+ public String getEntryDn(BigInteger a_id)
+ throws BackendException
+ {
+ return (String) m_nameIdx.getReverse(a_id) ;
+ }
+
+
+ public BigInteger getParentId(String a_dn)
+ throws BackendException, NamingException
+ {
+ BigInteger l_childId = m_nameIdx.getForward(a_dn) ;
+ return (BigInteger) m_hierarchyIdx.getReverse(l_childId) ;
+ }
+
+
+ public BigInteger getParentId(BigInteger a_childId)
+ throws BackendException
+ {
+ return (BigInteger) m_hierarchyIdx.getReverse(a_childId) ;
+ }
+
+
+ public int count()
+ throws BackendException
+ {
+ return m_master.count() ;
+ }
+
+
+ public int getIndexScanCount(String an_attribute)
+ throws BackendException, NamingException
+ {
+ return getIndex(an_attribute).count() ;
+ }
+
+
+ public int getIndexScanCount(String an_attribute, String a_value)
+ throws BackendException, NamingException
+ {
+ return getIndex(an_attribute).count(a_value) ;
+ }
+
+
+ public int getIndexScanCount(String an_attribute, String a_value,
+ boolean isGreaterThan)
+ throws BackendException, NamingException
+ {
+ return getIndex(an_attribute).count(a_value, isGreaterThan) ;
+ }
+
+
+ public boolean assertIndexValue(String an_attribute, Object a_value,
+ BigInteger a_id)
+ throws BackendException, NamingException
+ {
+ return getIndex(an_attribute).hasValue(a_value, a_id) ;
+ }
+
+
+ public boolean assertIndexValue(String an_attribute, Object a_value,
+ BigInteger a_id, boolean isGreaterThan)
+ throws BackendException, NamingException
+ {
+ return getIndex(an_attribute).hasValue(a_value, a_id, isGreaterThan) ;
+ }
+
+
+ public IndexCursor getIndexCursor(String an_attribute)
+ throws BackendException, NamingException
+ {
+ return getIndex(an_attribute).getCursor() ;
+ }
+
+
+ public IndexCursor getIndexCursor(String an_attribute, String a_value)
+ throws BackendException, NamingException
+ {
+ return getIndex(an_attribute).getCursor(a_value) ;
+ }
+
+
+ public IndexCursor getIndexCursor(String an_attribute, String a_value,
+ boolean isGreaterThan)
+ throws BackendException, NamingException
+ {
+ return getIndex(an_attribute).getCursor(a_value, isGreaterThan) ;
+ }
+
+
+ public IndexCursor getIndexCursor(String an_attribute, RE a_regex)
+ throws BackendException, NamingException
+ {
+ return getIndex(an_attribute).getCursor(a_regex) ;
+ }
+
+
+ public IndexCursor getIndexCursor(String an_attribute, RE a_regex,
+ String a_prefix)
+ throws BackendException, NamingException
+ {
+ return getIndex(an_attribute).getCursor(a_regex, a_prefix) ;
+ }
+
+
+ //////////////////////////////////
+ // Master Table CRUD Operations //
+ //////////////////////////////////
+
+
+ public void create(LdapEntryImpl an_entry, BigInteger a_id)
+ throws BackendException, NamingException
+ {
+ String l_ldif = m_schema.getLdifComposer().compose(an_entry) ;
+ m_master.put(l_ldif, a_id) ;
+ addIndices(an_entry) ;
+ an_entry.validate() ;
+ }
+
+
+ public LdapEntryImpl read(BigInteger a_id)
+ throws BackendException, NamingException
+ {
+ LdapEntryImpl l_entry = new LdapEntryImpl(this.m_schema) ;
+ l_entry.enableLogging(getLogger()) ;
+
+ String l_ldif = m_master.get(a_id) ;
+
+ if(getLogger().isDebugEnabled()) {
+ getLogger().debug("JdbmDatabase.read(BigInteger): Extracted the "
+ + "following LDIF from the master table:\n" + l_ldif) ;
+ }
+
+ try {
+ m_schema.getLdifParser().parse(l_entry, l_ldif) ;
+ } catch(ParseException e) {
+ throw new BackendException("Database may be corrupt. Cannot "
+ + "parse ldif entries in backing store.", e) ;
+ }
+
+ if(getLogger().isDebugEnabled()) {
+ getLogger().debug("JdbmDatabase.read(BigInteger): Resusitated the "
+ + "following entry using the ldif parser:\n" + l_entry) ;
+ }
+
+ l_entry.validate() ;
+ return l_entry ;
+ }
+
+
+ public void update(LdapEntryImpl an_entry)
+ throws BackendException, NamingException
+ {
+ String l_ldif = m_schema.getLdifComposer().compose(an_entry) ;
+ m_master.put(l_ldif, an_entry.getEntryID()) ;
+ updateIndices(an_entry) ;
+ an_entry.validate() ;
+ }
+
+
+ public void delete(BigInteger a_id)
+ throws BackendException, NamingException
+ {
+ if(getLogger().isDebugEnabled()) {
+ getLogger().debug("JdbmDatabase.delete(BigInteger): "
+ + "Deleting entry with id " + a_id) ;
+ }
+
+ LdapEntryImpl l_entry = read(a_id) ;
+
+ if(getLogger().isDebugEnabled()) {
+ getLogger().debug("JdbmDatabase.delete(BigInteger): "
+ + "Resusitated entry for deletion " + l_entry) ;
+ }
+
+ dropIndices(l_entry) ;
+ m_master.del(a_id) ;
+ }
+
+
+ /////////////////////////////
+ // Parent/Child Operations //
+ /////////////////////////////
+
+
+ public Cursor getChildren(BigInteger a_id)
+ throws BackendException, NamingException
+ {
+ return m_hierarchyIdx.getCursor(a_id) ;
+ }
+
+
+ public int getChildCount(BigInteger a_id)
+ throws BackendException, NamingException
+ {
+ return this.m_hierarchyIdx.count(a_id) ;
+ }
+
+
+ public Name getSuffix()
+ {
+ return m_suffix ;
+ }
+
+
+ public LdapEntryImpl getSuffixEntry()
+ throws BackendException, NamingException
+ {
+ return read(getEntryId(m_suffix.toString())) ;
+ }
+
+
+ public BigInteger getNextId()
+ throws BackendException
+ {
+ return m_master.getNextId() ;
+ }
+
+
+ public BigInteger getCurrentId()
+ throws BackendException
+ {
+ return m_master.getCurrentId() ;
+ }
+
+
+ public void sync()
+ {
+ Iterator l_list = m_indices.values().iterator() ;
+ while(l_list.hasNext()) {
+ Index l_index = (Index) l_list.next() ;
+
+ try {
+ l_index.sync() ;
+ } catch(Throwable t) {
+ super.getLogger().error("" //ProtocolModule.getMessageKey()
+ + " - Database.sync(): Failed to sync index on attribute "
+ + l_index.getAttribute()
+ + " - index data may be lost.", t) ;
+ }
+ }
+
+ try {
+ this.m_existanceIdx.sync() ;
+ } catch(Throwable t) {
+ getLogger().error("Failed to sync the existance table data may be "
+ + "lost.", t) ;
+ }
+
+ try {
+ this.m_hierarchyIdx.sync() ;
+ } catch(Throwable t) {
+ getLogger().error("Failed to sync the hierarchy table data may be "
+ + "lost.", t) ;
+ }
+
+ try {
+ this.m_nameIdx.sync() ;
+ } catch(Throwable t) {
+ getLogger().error("Failed to sync the distinguished name table "
+ + "data may be lost.", t) ;
+ }
+
+ try {
+ m_master.sync() ;
+ } catch(Throwable t) {
+ getLogger().error("Failed to sync the master table data may be "
+ + "lost.", t) ;
+ }
+ }
+
+
+ public void close()
+ {
+ Iterator l_list = m_indices.values().iterator() ;
+ while(l_list.hasNext()) {
+ Index l_index = (Index) l_list.next() ;
+
+ try {
+ l_index.close() ;
+ } catch(Throwable t) {
+ getLogger().error("Failed to close index on attribute "
+ + l_index.getAttribute()
+ + " - index data may be lost.", t) ;
+ }
+ }
+
+ try {
+ this.m_existanceIdx.close() ;
+ } catch(Throwable t) {
+ getLogger().error("Failed to close the existance table data may be "
+ + "lost.", t) ;
+ }
+
+ try {
+ this.m_hierarchyIdx.close() ;
+ } catch(Throwable t) {
+ getLogger().error("Failed to close the hierarchy table data may be "
+ + "lost.", t) ;
+ }
+
+ try {
+ this.m_nameIdx.close() ;
+ } catch(Throwable t) {
+ getLogger().error("Failed to close the distinguished name table "
+ + "data may be lost.", t) ;
+ }
+
+ try {
+ m_master.close() ;
+ } catch(Throwable t) {
+ getLogger().error("Failed to close the master table data may be "
+ + "lost.", t) ;
+ }
+
+ try {
+ m_recMan.close() ;
+ } catch(Throwable t) {
+ getLogger().error("Failed to close the database environment.", t) ;
+ }
+ }
+
+
+ public void enableLogging(Logger a_logger)
+ {
+ super.enableLogging(a_logger) ;
+ log = a_logger ;
+ m_nameIdx.enableLogging(a_logger) ;
+ m_existanceIdx.enableLogging(a_logger) ;
+ m_hierarchyIdx.enableLogging(a_logger) ;
+ m_master.enableLogging(a_logger) ;
+ }
+
+
+ /////////////////////
+ // Utility Methods //
+ /////////////////////
+
+
+ public void setProperty(String a_propertyName, String a_propertyValue)
+ throws BackendException
+ {
+ m_master.setProperty(a_propertyName, a_propertyValue) ;
+ }
+
+
+ public String getProperty(String a_propertyName)
+ throws BackendException
+ {
+ return this.m_master.getProperty(a_propertyName) ;
+ }
+
+
+ /**
+ * Lists only the User Defined Index (UDI) Attributes.
+ */
+ public Iterator getUDIAttributes()
+ {
+ return m_indices.keySet().iterator() ;
+ }
+
+
+ public final static String [] SYS_INDICES =
+ { Schema.DN_ATTR, Schema.EXISTANCE_ATTR, Schema.HIERARCHY_ATTR} ;
+
+ /**
+ * Gets the names of the maditory system indices used by the database.
+ * These names are used as the [operational] 'attribute' or key names
+ * of the indices. All cursor operations and assertion operations use
+ * these names to select the appropriate UDI (User Defined Index) or SDI
+ * (System Defined Index) to operate upon.
+ */
+ public String [] getSystemIndices()
+ {
+ return SYS_INDICES ;
+ }
+
+
+ public MultiMap getIndices(BigInteger a_id)
+ throws BackendException, NamingException
+ {
+ MultiHashMap l_map = new MultiHashMap() ;
+
+ // Get the distinguishedName to id mapping
+ l_map.put("distinguishedName", m_nameIdx.getReverse(a_id)) ;
+
+ // Get all standard index attribute to value mappings
+ Iterator l_indices = m_indices.values().iterator() ;
+ while(l_indices.hasNext()) {
+ Index l_index = (Index) l_indices.next() ;
+ Cursor l_cursor = l_index.getReverseCursor(a_id) ;
+ while(l_cursor.hasMore()) {
+ IndexRecord l_rec = (IndexRecord) l_cursor.next() ;
+ Object l_val = l_rec.getIndexKey() ;
+ l_map.put(l_index.getAttribute(), l_val) ;
+ }
+ }
+
+ // Get all existance mappings for this id creating a special key
+ // that looks like so 'existance[attribute]' and the value is set to id
+ Cursor l_cursor = m_existanceIdx.getReverseCursor(a_id) ;
+ StringBuffer l_val = new StringBuffer() ;
+ while(l_cursor.hasMore()) {
+ IndexRecord l_rec = (IndexRecord) l_cursor.next() ;
+ l_val.append("existance[").append(l_rec.getIndexKey()).append(']') ;
+ l_map.put(l_val.toString(), l_rec.getEntryId()) ;
+ l_val.setLength(0) ;
+ }
+
+ // Get all parent child mappings for this entry as the parent using the
+ // key 'child' with many entries following it.
+ l_cursor = this.m_hierarchyIdx.getCursor(a_id) ;
+ while(l_cursor.hasMore()) {
+ IndexRecord l_rec = (IndexRecord) l_cursor.next() ;
+ l_map.put("child", l_rec.getEntryId()) ;
+ }
+
+ return l_map ;
+ }
+
+
+ private void addIndices(LdapEntry an_entry)
+ throws BackendException, NamingException
+ {
+ BigInteger l_id = ((LdapEntryImpl) an_entry).getEntryID() ;
+ Iterator l_list = an_entry.attributes().iterator() ;
+
+ m_nameIdx.add(an_entry.getNormalizedDN().toString(), l_id) ;
+
+ if(getLogger().isDebugEnabled() && debug) {
+ getLogger().debug("Adding name index ("
+ + an_entry.getNormalizedDN().toString()
+ + ", " + l_id.toString() + ")") ;
+ }
+
+ m_hierarchyIdx.add(((LdapEntryImpl) an_entry).getParentID(), l_id) ;
+
+ while(l_list.hasNext()) {
+ String l_attribute = (String) l_list.next() ;
+ String l_tolower = l_attribute.toLowerCase() ;
+
+ if(m_indices.containsKey(l_tolower)) {
+ Index l_index = (Index) m_indices.get(l_tolower) ;
+ Iterator l_values = // Get values using correct case.
+ an_entry.getMultiValue(l_attribute).iterator() ;
+ while(l_values.hasNext()) {
+ l_index.add((String) l_values.next(), l_id) ;
+ }
+
+ // Existance index will never be hit since 'existance' is not an
+ // attribute based index in the formal sense. Nor are the name
+ // and hierarchy indices.
+ m_existanceIdx.add(l_tolower, l_id) ;
+ }
+ }
+ }
+
+
+ private void dropIndices(LdapEntry an_entry)
+ throws BackendException, NamingException
+ {
+ if(getLogger().isDebugEnabled()) {
+ getLogger().debug("JdbmModule.dropIndices(): deleting "
+ + "indices on entry\n" + an_entry) ;
+ }
+
+ BigInteger l_id = ((LdapEntryImpl) an_entry).getEntryID() ;
+ Iterator l_list = an_entry.attributes().iterator() ;
+
+ m_nameIdx.drop(an_entry.getNormalizedDN().toString(), l_id) ;
+ m_hierarchyIdx.drop(
+ ((LdapEntryImpl) an_entry).getParentID(), l_id) ;
+
+ while(l_list.hasNext()) {
+ String l_attribute = ((String) l_list.next()) ;
+ String l_tolower = l_attribute.toLowerCase() ;
+
+ if(m_indices.containsKey(l_tolower)) {
+ Index l_index = (Index) m_indices.get(l_tolower) ;
+ Iterator l_values = // Get values using correct case.
+ an_entry.getMultiValue(l_attribute).iterator() ;
+ while(l_values.hasNext()) {
+ l_index.drop((String) l_values.next(), l_id) ;
+ }
+
+ // Existance index will never be hit since 'existance' is not an
+ // attribute based index in the formal sense. Nor are the name
+ // and hierarchy indices.
+ m_existanceIdx.drop(l_tolower, l_id) ;
+ }
+ }
+ }
+
+
+ private void updateIndices( LdapEntryImpl an_entry )
+ throws BackendException, NamingException
+ {
+ if ( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug( "" //ProtocolModule.getMessageKey()
+ + " - Database.updateIndices() - dumping delta hashes "
+ + "after removing the old dn and adding the new Dn" ) ;
+ getLogger().debug( "Added hash:\n" + an_entry.getAdded() ) ;
+ getLogger().debug( "Removed hash:\n" + an_entry.getRemoved() ) ;
+ }
+
+ BigInteger l_id = an_entry.getEntryID() ;
+
+ //
+ // Remove indices for all attributes removed.
+ //
+
+ Iterator l_removedAttribs = an_entry.getRemoved().keySet().iterator() ;
+
+ while ( l_removedAttribs.hasNext() )
+ {
+ String l_removedAttrib = ( String ) l_removedAttribs.next() ;
+ String l_tolower = l_removedAttrib.toLowerCase() ;
+
+ if ( m_indices.containsKey( l_tolower ) )
+ {
+ Index l_index = ( Index ) m_indices.get( l_tolower ) ;
+
+ // Remove indices for all the removed values.
+ Iterator l_values = ( ( Collection )
+ an_entry.getRemoved().get( l_removedAttrib ) ).iterator() ;
+ while ( l_values.hasNext() )
+ {
+ Object l_val = l_values.next() ;
+ if ( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug( "" //ProtocolModule.getMessageKey()
+ + " - Database.updateIndices() - removing index "
+ + l_tolower + " with value " + l_val ) ;
+ }
+ l_index.drop( l_val, l_id ) ;
+ }
+
+ // Existance table must be handled specifically since it is not
+ // an [operational] attribute and is not caught by the loop
+ // above. We need to make sure that we only remove an existance
+ // index if all of the values for that attribute have been
+ // dropped. We also need to watch out for stale keys to empty
+ // collections in the multimap.
+ if ( ! an_entry.containsKey( l_removedAttrib ) )
+ {
+ m_existanceIdx.drop( l_tolower, l_id ) ;
+ }
+ else if ( an_entry.containsKey( l_removedAttrib ) &&
+ an_entry.getMultiValue( l_removedAttrib ).size() == 0 )
+ {
+ m_existanceIdx.drop( l_tolower, l_id ) ;
+ }
+ }
+ else if ( l_tolower.equals( "parentid" ) )
+ {
+ Iterator l_list = ( ( Collection )
+ an_entry.getRemoved().get( l_removedAttrib) ).iterator() ;
+
+ while( l_list.hasNext() )
+ {
+ BigInteger l_oldParentId = null ;
+ Object l_obj = l_list.next() ;
+
+ if ( l_obj instanceof String )
+ {
+ l_oldParentId = new BigInteger( ( String ) l_obj ) ;
+ }
+ else if ( l_obj instanceof BigInteger )
+ {
+ l_oldParentId = ( BigInteger ) l_obj ;
+ }
+
+
+ m_hierarchyIdx.drop( l_oldParentId, l_id ) ;
+
+ if( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug( "removed old parentid '"
+ + l_oldParentId + "' from hierarchy index" ) ;
+ }
+ }
+ } // Now we need to check for DN attribute changes due to modify ops
+ else if( l_tolower.equals( Schema.DN_ATTR ) )
+ {
+ Iterator l_list = ( ( Collection )
+ an_entry.getRemoved().get( l_removedAttrib ) ).iterator() ;
+
+ while( l_list.hasNext() )
+ {
+ Object l_oldDn = l_list.next() ;
+ m_nameIdx.drop( l_oldDn, l_id ) ;
+
+ if( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug( "removed old Dn '" + l_oldDn
+ + "' from name index" ) ;
+ }
+ }
+ } // Close else if
+ } // Close while
+
+
+ //
+ // Create indices for all attribute value pairs added.
+ //
+
+ Iterator l_addedAttribs = an_entry.getAdded().keySet().iterator() ;
+ while ( l_addedAttribs.hasNext() )
+ {
+ String l_addedAttrib = ( String ) l_addedAttribs.next() ;
+ String l_tolower = l_addedAttrib.toLowerCase() ;
+
+ if ( m_indices.containsKey( l_tolower ) )
+ {
+ Index l_index = ( Index ) m_indices.get( l_tolower ) ;
+
+ // Create indices for all the added values.
+ Iterator l_values = ( ( Collection )
+ an_entry.getAdded().get( l_addedAttrib ) ).iterator() ;
+ while ( l_values.hasNext() )
+ {
+ Object l_val = l_values.next() ;
+ l_index.add( l_val, l_id ) ;
+
+ if( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug( "" //ProtocolModule.getMessageKey()
+ + " - Database.updateIndices() - added index "
+ + l_tolower + " with value " + l_val ) ;
+ }
+ }
+
+ // Add an index into the existance table
+ m_existanceIdx.add( l_tolower, l_id ) ;
+ } // Now we need to check for DN attribute changes due to modify ops
+ else if ( l_tolower.equals( "parentid" ) )
+ {
+ Iterator l_list = ( ( Collection )
+ an_entry.getAdded().get( l_addedAttrib ) ).iterator() ;
+
+ while ( l_list.hasNext() )
+ {
+ BigInteger l_newParentId = null ;
+ Object l_obj = l_list.next() ;
+
+ if ( l_obj instanceof String )
+ {
+ l_newParentId = new BigInteger( ( String ) l_obj ) ;
+ }
+ else if ( l_obj instanceof BigInteger )
+ {
+ l_newParentId = ( BigInteger ) l_obj ;
+ }
+
+ m_hierarchyIdx.add( l_newParentId, l_id ) ;
+
+ if ( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug( "added new Dn '" + l_newParentId
+ + "' to hierarchy index" ) ;
+ }
+ }
+ }
+ else if ( l_tolower.equals( Schema.DN_ATTR ) )
+ {
+ Iterator l_list = ( ( Collection )
+ an_entry.getAdded().get( l_addedAttrib ) ).iterator() ;
+
+ while ( l_list.hasNext() )
+ {
+ String l_newDn = ( String ) l_list.next() ;
+ m_nameIdx.add( l_newDn, l_id ) ;
+
+ if ( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug( "added new Dn '"
+ + l_newDn + "' to name index" ) ;
+ }
+ }
+ } // Close else if
+ } // Close while
+ } // Close updateIndices()
+
+
+ /**
+ * Modifies the relative distinguished name (RDN) of an entry
+ * without changing any parent child relationships. This call
+ * has the side effect of altering the distinguished name of
+ * descendent entries if they exist. The boolean argument will
+ * optionally remove the existing RDN attribute value pair
+ * replacing it with the new RDN attribute value pair. If other
+ * RDN attribute value pairs exist besides the current RDN they
+ * will be spared.
+ *
+ * @param an_entry the entry whose RDN is to be modified.
+ * @param a_newRdn the new Rdn that is to replace the current Rdn.
+ * @param a_deleteOldRdn deletes the old Rdn attribute value pair if true.
+ * @throws BackendException when the operation cannot be performed due to a
+ * backing store error.
+ * @throws NamingException when naming violations and or schema violations
+ * occur due to attempting this operation.
+ */
+ public void modifyRdn( LdapEntryImpl an_entry,
+ String a_newRdn, boolean a_deleteOldRdn )
+ throws BackendException, NamingException
+ {
+ String l_attribute = NamespaceTools.getRdnAttribute( a_newRdn ) ;
+ String l_value = NamespaceTools.getRdnValue( a_newRdn ) ;
+
+ // This name is not Normalized since we want to preserve the user
+ // provided version of the Dn.
+ Name l_name = m_nonNormalizingParser.parse( an_entry.getEntryDN() ) ;
+
+ if ( a_deleteOldRdn ||
+ m_schema.isSingleValue( l_attribute.toLowerCase() ) )
+ {
+ String l_oldRdn = l_name.get( l_name.size() - 1 ) ;
+ String l_oldAttribute = NamespaceTools.getRdnAttribute( l_oldRdn ) ;
+ String l_oldValue = NamespaceTools.getRdnValue( l_oldRdn ) ;
+
+ an_entry.removeValue( l_oldAttribute, l_oldValue ) ;
+ }
+
+ l_name.remove( l_name.size() - 1 ) ;
+ l_name.add( l_name.size(), a_newRdn ) ;
+ an_entry.addValue( l_attribute, l_value ) ;
+
+ if( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug( "" //ProtocolModule.getMessageKey()
+ + " - Database.modifyRdn() - modifyDn() on entry '"
+ + an_entry.getEntryDN() + "' using new Dn of '"
+ + l_name + "'" ) ;
+ }
+
+ modifyDn( ( LdapEntryImpl ) an_entry, l_name) ;
+ }
+
+
+ /**
+ * Recursively modifies the distinguished name of an entry and the names of
+ * its descendants calling itself in the recursion.
+ *
+ * @param an_entry Entry being altered to have a new DN.
+ * @param a_dn Distinguished name to set as the new DN
+ */
+ void modifyDn(LdapEntryImpl an_entry, Name a_dn)
+ throws BackendException, NamingException
+ {
+ LdapEntryImpl l_child ;
+ Cursor l_children ;
+ Name l_childDN ;
+
+ if ( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug( "" //ProtocolModule.getMessageKey()
+ + " - Database.modifyDn() - called on entry '"
+ + an_entry.getNormalizedDN() + "' to change it's DN to '"
+ + a_dn ) ;
+ }
+
+ // Package friendly method that sets the user provided dn using
+ // a name. It automatically updates the normalized dn so it is
+ // synchronized with the change. setEntryDN must add the
+ // appropriate hints in the entry so the update can properly modify
+ // indices. If it seems like too much of a hassle then we can
+ // handle index maintenance here with replication of update function
+ // -ality.
+ an_entry.setEntryDN( a_dn ) ;
+ update( an_entry ) ;
+ l_children = getChildren( an_entry.getEntryID() ) ;
+
+ // List children using the DN since the updated parent has had
+ // it's indices updated listChildren will lookup the id by dn
+ // then use the parent child index to lookup all the children.
+ while( l_children.hasMore() )
+ {
+ IndexRecord l_rec = ( IndexRecord ) l_children.next() ;
+ l_child = read( l_rec.getEntryId() ) ;
+ l_childDN = ( Name ) a_dn.clone() ;
+
+ // Add to the copy of the parent the unnormalized rdn of the child
+ // Dn to get the new Dn of the child entry - call recursively.
+ l_childDN.add( 0,
+ NamespaceTools.getRdn( l_child.getEntryDN() ) ) ;
+ modifyDn( l_child, l_childDN ) ;
+ }
+ }
+
+
+ /**
+ * This overload combines the first two method operations into one.
+ * It changes the Rdn and the parent prefix at the same time while
+ * recursing name changes to all descendants of the child entry. It
+ * is obviously more complex than the other two operations alone and
+ * involves changes to both parent child indices and DN indices.
+ *
+ * @param a_parentEntry the parent the child is to subordinate to.
+ * @param a_childEntry the child to be moved under the parent.
+ * @param a_newRdn the new Rdn that is to replace the current Rdn.
+ * @param a_deleteOldRdn deletes the old Rdn attribute value pair if true.
+ * @throws BackendException when the operation cannot be performed due to a
+ * backing store error.
+ * @throws NamingException when naming violations and or schema violations
+ * occur due to attempting this operation.
+ */
+ public void move(LdapEntryImpl a_parentEntry, LdapEntryImpl a_childEntry,
+ String a_newRdn, boolean a_deleteOldRdn)
+ throws BackendException, NamingException
+ {
+ // @TODO NOT A VERY EFFICENT OPERATION AT ALL ! ! ! FIX IT ! ! !
+ ( ( LdapEntryImpl ) a_childEntry ).setParent( ( LdapEntryImpl )
+ a_parentEntry ) ;
+ modifyRdn( a_childEntry, a_newRdn, a_deleteOldRdn ) ;
+ move( a_parentEntry, a_childEntry ) ;
+ }
+
+
+ /**
+ * Moves a child entry without changing the RDN under a new parent
+ * entry. This effects the parent child relationship between the
+ * parent entry and the child entry. The index for the child
+ * mapping it to the current parent is destroyed and a new index
+ * mapping it to the new parent is created. As a side effect the
+ * name of the child entry and all its descendants will reflect the
+ * move within the DIT to a new parent. The old parent prefix to
+ * the distinguished names of the child and its descendents will be
+ * replaced by the new parent DN prefix.
+ *
+ * @param a_parentEntry the parent the child is to subordinate to.
+ * @param a_childEntry the child to be moved under the parent.
+ * @throws BackendException when the operation cannot be performed due to a
+ * backing store error.
+ * @throws NamingException when naming violations and or schema violations
+ * occur due to attempting this operation.
+ */
+ public void move( LdapEntryImpl a_parentEntry, LdapEntryImpl a_childEntry )
+ throws BackendException, NamingException
+ {
+ Name l_parentDn =
+ m_nonNormalizingParser.parse( a_parentEntry.getEntryDN() ) ;
+ Name l_childDn =
+ m_nonNormalizingParser.parse( a_childEntry.getEntryDN() ) ;
+ String l_rdn = l_childDn.get( l_childDn.size() - 1 ) ;
+
+ // This call should be package friendly and should automatically
+ // replace the current parent id and dn operational attributes
+ // with the new parent's respective operational attribute values.
+ ( ( LdapEntryImpl ) a_childEntry ).setParent(
+ ( LdapEntryImpl ) a_parentEntry ) ;
+
+ Name l_newDn = l_parentDn ;
+ l_newDn.add( l_newDn.size(), l_rdn ) ;
+ modifyDn( ( LdapEntryImpl ) a_childEntry, l_newDn ) ;
+ }
+}
+
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/JdbmModule.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/JdbmModule.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,596 @@
+/*
+ * $Id: JdbmModule.java,v 1.11 2003/08/06 03:01:25 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm ;
+
+
+import java.math.BigInteger ;
+
+import javax.naming.Name ;
+import javax.naming.NamingException ;
+import javax.naming.NameNotFoundException ;
+import javax.naming.ContextNotEmptyException ;
+import javax.naming.NameAlreadyBoundException ;
+
+import org.apache.eve.backend.Cursor ;
+import org.apache.ldap.common.filter.ExprNode ;
+import org.apache.eve.backend.LdapEntry ;
+import org.apache.eve.schema.SchemaManager ;
+import org.apache.eve.backend.BackendModule ;
+import org.apache.eve.backend.BackendException ;
+import org.apache.eve.backend.jdbm.search.SearchEngine ;
+
+import org.apache.avalon.framework.ExceptionUtil ;
+import org.apache.avalon.framework.service.ServiceManager ;
+import org.apache.avalon.framework.service.ServiceException ;
+import org.apache.avalon.framework.configuration.Configuration ;
+import org.apache.avalon.framework.configuration.ConfigurationException ;
+
+import org.apache.commons.collections.LRUMap ;
+import org.apache.eve.backend.jdbm.gui.BackendFrame ;
+
+
+/**
+ * Jdbm backend module.
+ *
+ * @phoenix:block
+ * @phoenix:service name="org.apache.eve.backend.AtomicBackend"
+ * @phoenix:mx-topic name="jdbm-backend"
+ */
+public class JdbmModule
+ extends BackendModule
+{
+ private JdbmDatabase m_db = null ;
+ private SearchEngine m_searchEngine = null ;
+
+ private Object m_cacheLock = new Object() ;
+ private LRUMap m_byIdCache = new LRUMap() ;
+
+
+ public JdbmDatabase getDatabase()
+ {
+ return m_db ;
+ }
+
+
+ private void addToCache(org.apache.eve.backend.jdbm.LdapEntryImpl an_entry)
+ throws NamingException
+ {
+ synchronized(m_cacheLock) {
+ super.m_cache.put(an_entry.getNormalizedDN().toString(), an_entry) ;
+ this.m_byIdCache.put(an_entry.getEntryID(), an_entry) ;
+ }
+ }
+
+
+ private void removeFromCache(org.apache.eve.backend.jdbm.LdapEntryImpl an_entry)
+ throws NamingException
+ {
+ synchronized(m_cacheLock) {
+ super.m_cache.remove(an_entry.getNormalizedDN().toString()) ;
+ this.m_byIdCache.remove(an_entry.getEntryID()) ;
+ }
+ }
+
+
+ //////////////////////////////////
+ // Backend Crud Implementations //
+ //////////////////////////////////
+
+
+ public void delete( LdapEntry an_entry )
+ throws BackendException, NamingException
+ {
+ LdapEntryImpl l_entry = ( LdapEntryImpl ) an_entry ;
+
+ if( ! l_entry.isValid() )
+ {
+ throw new BackendException( "Cannot perform delete operation on "
+ + "invalid entry: " + l_entry ) ;
+ }
+
+ if( m_db.getChildCount( l_entry.getEntryID() ) > 0 )
+ {
+ // Exception translates to NOTALLOWEDONLEAF LDAPv3 result code (66)
+ ContextNotEmptyException e = new ContextNotEmptyException(
+ "[66] Cannot delete entry " + l_entry.getEntryDN()
+ + " it has children!" ) ;
+ e.setRemainingName( l_entry.getNormalizedDN() ) ;
+ throw e ;
+ }
+
+ BigInteger l_id = l_entry.getEntryID() ;
+ m_db.delete( l_id ) ;
+ removeFromCache( ( LdapEntryImpl ) an_entry ) ;
+ }
+
+
+ /**
+ * Creates a new invalid entry ready to be populated and created within this
+ * backend module.
+ *
+ * @param a_dn the non-normalized user provided distinguished name of the
+ * new entry to create.
+ * @throws NameAlreadyBoundException if an entry with a_dn already exists
+ * within this backend.
+ * @throws javax.naming.InvalidNameException if a_dn does not conform to the dn syntax
+ * @throws NameNotFoundException if a_dn is not suffix and does not have a
+ * parent to be attached to.
+ */
+ public LdapEntry newEntry( String a_dn )
+ throws BackendException, NamingException
+ {
+ // Will throw InvalidNameException if a_dn is syntactically incorrect.
+ Name l_dn = m_schema.getNormalizingParser().parse( a_dn ) ;
+ if( m_db.getEntryId( l_dn.toString() ) != null )
+ {
+ // NameAlreadyBoundExceptions correspond to a NAMEALREADYEXISTS
+ // result code with a value of [68] within the LDAPv3 protocol.
+ NameAlreadyBoundException e = new NameAlreadyBoundException(
+ "[68] '" + a_dn + "' is already bound." ) ;
+ e.setResolvedName( l_dn ) ;
+ throw e ;
+ }
+
+ //
+ // We only check for the existance of a parent entry if the new entry
+ // to add is not a suffix. This is because a suffix entry will not
+ // have a parent node.
+ //
+
+ if( ! l_dn.equals( getSuffix() ) )
+ {
+ Name l_parent = l_dn.getSuffix( 1 ) ;
+ if( m_db.getEntryId( l_parent.toString() ) == null )
+ {
+ // NameNotFoundExceptions in JNDI correspond to the NOSUCHOBJECT
+ // result code of the LdapResult of the response in LDAPv3
+ NameNotFoundException e = new NameNotFoundException(
+ "[32] Parent entry '" + l_parent
+ + "' does not exist. Cannot create " + l_dn.get(0)
+ + " without parent." ) ;
+ throw e ;
+ }
+ }
+
+ LdapEntryImpl l_entry = new LdapEntryImpl( m_schema, l_dn, a_dn ) ;
+ l_entry.enableLogging( getLogger() ) ;
+ return l_entry ;
+ }
+
+
+ public LdapEntry read( Name a_dn )
+ throws BackendException, NamingException
+ {
+ if( m_cache.containsKey( a_dn.toString() ) )
+ {
+ return ( LdapEntry ) m_cache.get( a_dn.toString() ) ;
+ }
+
+ BigInteger l_id = m_db.getEntryId( a_dn.toString() ) ;
+
+ if( l_id == null )
+ {
+ throw new NameNotFoundException( "[32] '" + a_dn
+ + "' does not exist!" ) ;
+ }
+
+ LdapEntryImpl l_entry = m_db.read( l_id ) ;
+ l_entry.enableLogging( getLogger() ) ;
+ addToCache( l_entry ) ;
+ return l_entry ;
+ }
+
+
+ LdapEntry read(BigInteger l_id)
+ throws BackendException, NamingException
+ {
+ if(this.m_byIdCache.containsKey(l_id)) {
+ return (LdapEntry) m_byIdCache.get(l_id) ;
+ }
+
+ LdapEntryImpl l_entry = m_db.read(l_id) ;
+ l_entry.enableLogging(getLogger()) ;
+ addToCache(l_entry) ;
+ return l_entry ;
+ }
+
+
+ /**
+ * Updates an entry in the backing store.
+ *
+ * @param an_entry the modified entry to update.
+ */
+ public void update(LdapEntry an_entry)
+ throws BackendException, NamingException
+ {
+ removeFromCache((LdapEntryImpl) an_entry) ;
+ m_db.update((LdapEntryImpl) an_entry) ;
+ addToCache((LdapEntryImpl) an_entry) ;
+ }
+
+
+ public void create(LdapEntry an_entry)
+ throws BackendException, NamingException
+ {
+ LdapEntryImpl l_entry = (LdapEntryImpl) an_entry ;
+
+ if(l_entry.isValid()) {
+ throw new BackendException("Cannot create entries that have "
+ + "already been created!") ;
+ }
+
+ // Add operational attributes!
+ BigInteger l_id = m_db.getNextId() ;
+ LdapEntryImpl l_parent = null ;
+ BigInteger l_parentId = null ;
+ l_entry.put(LdapEntry.ID_ATTR, l_id.toString()) ;
+
+ if(l_entry.getNormalizedDN().equals(m_suffix)) {
+ l_entry.put(LdapEntry.PARENTID_ATTR, l_id.toString()) ;
+ l_entry.put(LdapEntry.PARENTDN_ATTR, l_entry.getEntryDN()) ;
+ l_parent = l_entry ;
+ l_parentId = l_id ;
+ } else {
+ l_parent = (LdapEntryImpl) getParent(l_entry.getNormalizedDN()) ;
+ l_parentId = l_parent.getEntryID() ;
+ l_entry.put(LdapEntry.PARENTID_ATTR, l_parentId.toString()) ;
+ l_entry.put(LdapEntry.PARENTDN_ATTR, l_parent.getEntryDN()) ;
+ }
+
+ m_db.create(l_entry, l_id) ;
+ addToCache(l_entry) ;
+ }
+
+
+ ///////////////////////////////////////
+ // Search and Modify Implementations //
+ ///////////////////////////////////////
+
+
+ /**
+ * Searches for candidate entries on the backend starting on a base DN
+ * using a search filter with search controls.
+ *
+ * The distinguished name argument is NOT presumed to be normalized in
+ * accordance with schema attribute syntax and attribute matching rules.
+ * The DN is also NOT presumed to be syntacticly correct or within the
+ * namespace of this directory information base. Unaware of normalization
+ * this method will attempt to normalize any DN arguements. Apriori
+ * normalization would be redundant.
+ *
+ * W O R K I N P R O G R E S S
+ *
+ * @param a_filter String representation of an LDAP search filter.
+ * @param a_baseDn String representing the base of the search.
+ * @param a_scope SearchControls governing how this search is to be
+ * conducted.
+ * @throws BackendException on Backend errors or when the operation cannot
+ * proceed due to a malformed search filter, a non-existant search base, or
+ * inconsistant search controls.
+ * @throws javax.naming.InvalidNameException if a_baseDN is not syntactically correct.
+ * @throws NameNotFoundException when a component of a_baseDN cannot be
+ * resolved because it is not bound.
+ * @throws javax.naming.directory.InvalidSearchFilterException when the specification of a search
+ * filter is invalid. The expression of the filter may be invalid, or there
+ * may be a problem with one of the parameters passed to the filter.
+ * @throws javax.naming.directory.InvalidSearchControlsException when the specification of the
+ * SearchControls for a search operation is invalid. For example, if the
+ * scope is set to a value other than OBJECT_SCOPE, ONELEVEL_SCOPE,
+ * SUBTREE_SCOPE, this exception is thrown.
+ */
+ public Cursor search(ExprNode a_filter, Name a_baseDn, int a_scope)
+ throws BackendException, NamingException
+ {
+ Cursor l_cursor = new EntryCursor(this,
+ m_searchEngine.search(m_db, a_filter,
+ a_baseDn.toString(), a_scope)) ;
+ l_cursor.enableLogging(getLogger()) ;
+ return l_cursor ;
+ }
+
+
+ /**
+ * Modifies the relative distinguished name (RDN) of an entry
+ * without changing any parent child relationships. This call
+ * has the side effect of altering the distinguished name of
+ * descendent entries if they exist. The boolean argument will
+ * optionally remove the existing RDN attribute value pair
+ * replacing it with the new RDN attribute value pair. If other
+ * RDN attribute value pairs exist besides the current RDN they
+ * will be spared.
+ *
+ * @param an_entry the entry whose RDN is to be modified.
+ * @param a_newRdn the new Rdn that is to replace the current Rdn.
+ * @param a_deleteOldRdn deletes the old Rdn attribute value pair if true.
+ * @throws BackendException when the operation cannot be performed due to a
+ * backing store error.
+ * @throws NamingException when naming violations and or schema violations
+ * occur due to attempting this operation.
+ */
+ public void modifyRdn( LdapEntry an_entry, Name a_newRdn,
+ boolean a_deleteOldRdn )
+ throws BackendException, NamingException
+ {
+ m_db.modifyRdn( ( LdapEntryImpl ) an_entry,
+ a_newRdn.toString(), a_deleteOldRdn ) ;
+ }
+
+
+ /**
+ * Moves a child entry without changing the RDN under a new parent
+ * entry. This effects the parent child relationship between the
+ * parent entry and the child entry. The index for the child
+ * mapping it to the current parent is destroyed and a new index
+ * mapping it to the new parent is created. As a side effect the
+ * name of the child entry and all its descendants will reflect the
+ * move within the DIT to a new parent. The old parent prefix to
+ * the distinguished names of the child and its descendents will be
+ * replaced by the new parent DN prefix.
+ *
+ * @param a_parentEntry the parent the child is to subordinate to.
+ * @param a_childEntry the child to be moved under the parent.
+ * @throws BackendException when the operation cannot be performed due to a
+ * backing store error.
+ * @throws NamingException when naming violations and or schema violations
+ * occur due to attempting this operation.
+ */
+ public void move( LdapEntry a_parentEntry, LdapEntry a_childEntry )
+ throws BackendException, NamingException
+ {
+ m_db.move( ( LdapEntryImpl ) a_parentEntry,
+ ( LdapEntryImpl ) a_childEntry) ;
+ }
+
+
+ /**
+ * This overload combines the first two method operations into one.
+ * It changes the Rdn and the parent prefix at the same time while
+ * recursing name changes to all descendants of the child entry. It
+ * is obviously more complex than the other two operations alone and
+ * involves changes to both parent child indices and DN indices.
+ *
+ * @param a_parentEntry the parent the child is to subordinate to.
+ * @param a_childEntry the child to be moved under the parent.
+ * @param a_newRdn the new Rdn that is to replace the current Rdn.
+ * @param a_deleteOldRdn deletes the old Rdn attribute value pair if true.
+ * @throws BackendException when the operation cannot be performed due to a
+ * backing store error.
+ * @throws NamingException when naming violations and or schema violations
+ * occur due to attempting this operation.
+ */
+ public void move( LdapEntry a_parentEntry, LdapEntry a_childEntry,
+ Name a_newRdn, boolean a_deleteOldRdn )
+ throws BackendException, NamingException
+ {
+ m_db.move( ( LdapEntryImpl ) a_parentEntry,
+ ( LdapEntryImpl ) a_childEntry,
+ a_newRdn.toString(), a_deleteOldRdn ) ;
+ }
+
+
+ ///////////////////////////////////////
+ // Remaining Backend Implementations //
+ ///////////////////////////////////////
+
+
+ public LdapEntry getParent(Name a_childDN)
+ throws BackendException, NamingException
+ {
+ return read(a_childDN.getSuffix(1)) ;
+ }
+
+
+ public boolean hasEntry(Name a_dn)
+ throws BackendException, NamingException
+ {
+ return m_db.getEntryId(a_dn.toString())
+ != null ;
+ }
+
+
+ public boolean isSuffix(LdapEntry an_entry)
+ throws NamingException
+ {
+ return an_entry.getNormalizedDN().equals(m_suffix) ;
+ }
+
+
+ public boolean isAdminUser(Name a_userDn)
+ throws NamingException
+ {
+ if(a_userDn.equals(m_adminUser)) {
+ return true ;
+ }
+
+ return false ;
+ }
+
+
+ public Cursor listChildren(Name a_parentDN)
+ throws BackendException, NamingException
+ {
+ BigInteger l_id =
+ m_db.getEntryId(a_parentDN.toString()) ;
+
+ if(l_id == null) {
+ throw new NameNotFoundException("Cannot list the children of "
+ + a_parentDN + ". It does not exist!") ;
+ }
+
+ Cursor l_cursor = new EntryCursor(this, m_db.getChildren(l_id)) ;
+ l_cursor.enableLogging(getLogger()) ;
+ return l_cursor ;
+ }
+
+
+ public String getProperty(String a_propertyName)
+ throws BackendException
+ {
+ return m_db.getProperty(a_propertyName) ;
+ }
+
+
+ public void setProperty(String a_propertyName, String a_propertyValue)
+ throws BackendException
+ {
+ m_db.setProperty(a_propertyName, a_propertyValue) ;
+ }
+
+
+ public String getImplementationRole()
+ {
+ return ROLE ;
+ }
+
+
+ /**
+ * @phoenix:mx-attribute
+ * @phoenix:mx-description Returns the implementation name.
+ * @phoenix:mx-isWriteable no
+ */
+ public String getImplementationName()
+ {
+ return("Jdbm DB Implementation") ;
+ }
+
+
+ /**
+ * @phoenix:mx-attribute
+ * @phoenix:mx-description Returns the implementation class name.
+ * @phoenix:mx-isWriteable no
+ */
+ public String getImplementationClassName()
+ {
+ return this.getClass().getName() ;
+ }
+
+
+ /**
+ * @phoenix:mx-attribute
+ * @phoenix:mx-description Returns the suffix of this backend.
+ * @phoenix:mx-isWriteable no
+ */
+ public Name getSuffix()
+ {
+ return m_db.getSuffix() ;
+ }
+
+
+ /**
+ * @phoenix:mx-operation
+ * @phoenix:mx-description Synchronizes cached berkeley data with disk.
+ */
+ public void sync()
+ throws BackendException
+ {
+ m_db.sync() ;
+ }
+
+
+ /**
+ * @phoenix:mx-operation
+ * @phoenix:mx-description Invokes the admin tool gui.
+ */
+ public void invokeAdminTool()
+ throws Exception
+ {
+ try {
+ BackendFrame l_frame = new BackendFrame() ;
+ l_frame.enableLogging(getLogger()) ;
+ l_frame.loadDatabase(m_db) ;
+ l_frame.launch() ;
+ } catch(Exception e) {
+ getLogger().error("Got the following exception while trying to "
+ + "invoke the admin tool: " + e.getMessage() + "\n\nTrace:\n"
+ + ExceptionUtil.printStackTrace(e)) ;
+ }
+ }
+
+
+ /////////////////////////////////////////////
+ // Configuration Interface Implementations //
+ /////////////////////////////////////////////
+
+ public static final String INDICES_TAG = "indices" ;
+ public static final String INDEX_TAG = "index" ;
+ public static final String INAME_ATTR = "name" ;
+
+ /**
+ * Avalon Configurable interface implementation specific to a Berkeley Db.
+ * Here's an example configuration with a "cn" and ""dc" index. Notice
+ * that the standard backend configuration attributes are not included:<br>
+ *
+ * <config>
+ * <backend>
+ * <indices>
+ * <index name="cn"/>
+ * <index name="dc"/>
+ * </indices>
+ * </backend>
+ * </config>
+ *
+ * @param a_config an avalon configuration object for this backend block.
+ * @throws ConfigurationException if the configuration is not correct.
+ */
+ public void configure(Configuration a_config)
+ throws ConfigurationException
+ {
+ super.configure(a_config) ;
+
+ ///////////////////////////////////////////////
+ // Configure Backend Database and Components //
+ ///////////////////////////////////////////////
+
+ try {
+ m_byIdCache.setMaximumSize(m_cache.getMaximumSize()) ;
+ m_searchEngine = new SearchEngine() ;
+ m_searchEngine.enableLogging(getLogger()) ;
+ m_db = new JdbmDatabase (m_schema, m_suffix, m_wkdirPath) ;
+ m_db.enableLogging(getLogger()) ;
+
+ Configuration [] l_indices =
+ a_config.getChild(INDICES_TAG).getChildren(INDEX_TAG) ;
+ String l_attribName = null ;
+ for(int ii = 0; ii < l_indices.length; ii++) {
+ l_attribName = l_indices[ii].getAttribute(INAME_ATTR) ;
+ m_db.addIndexOn(l_attribName) ;
+ }
+ } catch(NamingException e) {
+ throw new ConfigurationException("Could not configure "
+ + getImplementationName() + " with suffix " + m_suffix
+ + " due to NamingException:\n" + e.getMessage(), e) ;
+ } catch(BackendException e) {
+ throw new ConfigurationException("Could not configure "
+ + getImplementationName() + " with suffix " + m_suffix
+ + " due to NamingException:\n" + e.getMessage(), e) ;
+ }
+ }
+
+
+ public void stop()
+ throws Exception
+ {
+ super.stop() ;
+ m_db.close() ;
+ }
+
+
+ /**
+ * @phoenix:dependency name="org.apache.eve.schema.SchemaManager"
+ * @phoenix:dependency name="org.apache.eve.backend.UnifiedBackend"
+ */
+ public void service(ServiceManager a_manager)
+ throws ServiceException
+ {
+ super.service(a_manager) ;
+ m_schemaManager =
+ (SchemaManager) a_manager.lookup(SchemaManager.ROLE) ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/LdapEntryImpl.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/LdapEntryImpl.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,850 @@
+/*
+ * $Id: LdapEntryImpl.java,v 1.9 2003/08/06 03:01:25 akarasulu Exp $
+ * $Prologue$
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm ;
+
+
+import java.util.Date ;
+import java.util.HashMap ;
+import java.util.Iterator ;
+import java.util.Collection ;
+import java.math.BigInteger ;
+
+import javax.naming.Name ;
+import javax.naming.NamingException ;
+import javax.naming.directory.AttributeInUseException ;
+import javax.naming.directory.InvalidAttributeValueException ;
+import javax.naming.directory.AttributeModificationException ;
+import javax.naming.directory.InvalidAttributeIdentifierException ;
+
+import org.apache.ldap.common.util.NamespaceTools ;
+import org.apache.eve.backend.LdapEntry ;
+import org.apache.eve.schema.Schema ;
+import org.apache.eve.protocol.ProtocolModule;
+
+import org.apache.avalon.framework.logger.Logger ;
+import org.apache.avalon.framework.logger.LogEnabled ;
+
+import org.apache.commons.collections.LRUMap ;
+import org.apache.commons.collections.MultiHashMap ;
+import org.apache.ldap.common.name.DnParser;
+
+
+/**
+ * An entry implementation for the Berkeley backend.
+ *
+ * @task No schema checking going on right now - but this needs to change!
+ * @task Also we need to make sure that we are storing dates in the apropriate
+ * fashion
+ */
+public class LdapEntryImpl
+ extends MultiHashMap
+ implements LdapEntry, LogEnabled
+{
+ private final Schema m_schema ;
+ private Logger m_log ;
+ private Name m_normalizedDn ;
+ private Name m_dn ;
+ private boolean m_isValid = false ;
+ private BigInteger m_id ;
+ private HashMap m_attrIdMap = new HashMap() ;
+ private LRUMap m_attrIdCache = new LRUMap(25) ;
+
+ // Only used on validated entries - validation initializes them.
+ private MultiHashMap m_added = null ;
+ private MultiHashMap m_removed = null ;
+
+
+ LdapEntryImpl( Schema a_schema, Name a_dName, String a_dnStr )
+ {
+ m_schema = a_schema ; // schema this entry uses
+ m_normalizedDn = a_dName ; // normalized parsed name
+ put( DN_ATTR, a_dnStr ) ; // user provided name
+ }
+
+
+ LdapEntryImpl(Schema a_schema)
+ {
+ m_schema = a_schema ;
+ }
+
+
+ /**
+ * Note that according to the Backend-Server contract this method must
+ * return a Collection of attribute identifier names as they were
+ * specified by the user at creation time. These are not normalized
+ * attribute identifiers.
+ */
+ public Collection attributes()
+ {
+ return this.keySet() ;
+ }
+
+
+ public Schema getSchema()
+ {
+ return m_schema ;
+ }
+
+
+ public boolean equals(String a_dn)
+ throws NamingException
+ {
+ String l_normalized = m_schema.normalize(Schema.DN_ATTR, a_dn) ;
+ Name l_name = this.getNormalizedDN() ;
+ return l_name.toString().equals(l_normalized) ;
+ }
+
+
+ public boolean hasAttribute(String an_attributeName)
+ {
+ return containsKey(an_attributeName) ;
+ }
+
+
+ public boolean hasAttributeValuePair(String an_attribute, Object a_value)
+ {
+ if(containsKey(an_attribute)) {
+ Collection l_collection = getMultiValue(an_attribute) ;
+
+ if(null == l_collection && null == a_value) {
+ return true ;
+ } else if(null == l_collection || null == a_value) {
+ return false ;
+ } else if(l_collection.contains(a_value)) {
+ return true ;
+ } else {
+ return false ;
+ }
+ } else {
+ return false ;
+ }
+ }
+
+
+ /**
+ * Gets this entry's creation timestamp as a Date.
+ *
+ * @return Date representing the creation timestamp of this entry.
+ */
+ public Date getCreateTimestamp()
+ {
+ return new Date((String) getSingleValue(CREATETIMESTAMP_ATTR)) ;
+ }
+
+
+ /**
+ * Gets the distinguished name of the creator of this entry.
+ *
+ * The distinguished name is presumed to be normalized by the server naming
+ * subsystem in accordance with schema attribute syntax and attribute
+ * matching rules. The DN is also presumed to be syntacticly correct and
+ * within the namespace of this directory information base from which this
+ * Entry originated.
+ *
+ * @return the distinguished name of the creator.
+ */
+ public String getCreatorsName()
+ {
+ return (String) getSingleValue(CREATORSNAME_ATTR) ;
+ }
+
+
+ /**
+ * Gets the unique distinguished name associated with this entry as it was
+ * supplied during creation without whitespace trimming or character case
+ * conversions. This version of the DN is kept within the body of this
+ * Entry as an operational attribute so that it could be returned as it was
+ * given to the server w/o normalization effects: case and whitespace will
+ * be entact.
+ *
+ * @return the distinguished name of this entry as a String.
+ */
+ public String getEntryDN()
+ {
+ return (String) getSingleValue(DN_ATTR) ;
+ }
+
+
+ /**
+ * Gets the unique identifier of this entry as a BigInteger.
+ *
+ * @return BigInteger unique identifier of this entry.
+ */
+ public BigInteger getEntryID()
+ {
+ if(m_id == null) {
+ m_id = new BigInteger((String) getSingleValue(ID_ATTR)) ;
+ }
+
+ return m_id ;
+ }
+
+
+ /**
+ * Gets the distinguished name of the last modifier of this entry.
+ *
+ * The distinguished name is presumed to be normalized by the server naming
+ * subsystem in accordance with schema attribute syntax and attribute
+ * matching rules. The DN is also presumed to be syntacticly correct and
+ * within the namespace of this directory information base from which this
+ * Entry originated.
+ *
+ * @return the DN of the user to modify this entry last.
+ */
+ public String getModifiersName()
+ {
+ return (String) getSingleValue(MODIFIERSNAME_ATTR) ;
+ }
+
+
+ /**
+ * Gets this entry's modification timestamp as a Date.
+ *
+ * @return Date representing the timestamp this entry was last modified.
+ */
+ public Date getModifyTimestamp()
+ {
+ return new Date((String)
+ getSingleValue(MODIFYTIMESTAMP_ATTR)) ;
+ }
+
+
+ /**
+ * Gets the normalized unique distinguished name associated with this
+ * entry. This DN unlike the user specified DN accessed via getDN() is not
+ * an operational attribute composing the body of this Entry.
+ *
+ * The distinguished name is presumed to be normalized by the server naming
+ * subsystem in accordance with schema attribute syntax and attribute
+ * matching rules. The DN is also presumed to be syntacticly correct and
+ * within the namespace of this directory information base from which this
+ * Entry originated.
+ *
+ * @return the normalized distinguished name of this entry as a String.
+ */
+ public Name getNormalizedDN()
+ throws NamingException
+ {
+ if(m_normalizedDn == null) {
+ m_normalizedDn =
+ m_schema.getNormalizingParser().parse(getEntryDN()) ;
+ }
+
+ return m_normalizedDn;
+ }
+
+
+ /**
+ * Gets a Name representation of the originally user provided name without
+ * any case conversions. I added this method so we can cache this value
+ * and avoid the reparse via the use of the nexus getName method.
+ */
+ public Name getUnNormalizedDN()
+ throws NamingException
+ {
+ if(m_dn == null) {
+ m_dn = m_schema.getNameParser().parse(getEntryDN()) ;
+ }
+
+ return m_dn ;
+ }
+
+
+ /**
+ * Gets the number of subordinate child entries that exist for this Entry.
+ *
+ * @return the number of subordinates (children).
+ */
+ public BigInteger getNumSubordinates()
+ {
+ return new BigInteger((String)
+ getSingleValue(NUMSUBORDINATES_ATTR)) ;
+ }
+
+
+ /**
+ * Gets the normalized unique distinguished name of this Entry's parent.
+ *
+ * The distinguished name is presumed to be normalized by the server naming
+ * subsystem in accordance with schema attribute syntax and attribute
+ * matching rules. The DN is also presumed to be syntacticly correct and
+ * within the namespace of this directory information base from which this
+ * Entry originated.
+ *
+ * @return the normalized distinguished name of this Entry's parent.
+ */
+ public String getParentDN()
+ {
+ return (String) getSingleValue(PARENTDN_ATTR) ;
+ }
+
+
+ /**
+ * Gets the unique identifier of this entry's parent entry as a BigInteger.
+ * The parent ID is equal to the entry id <code>
+ * (getEntryID().equals(parentID()) == true) </code> if this entry is a
+ * root (a.k.a. suffix) entry.
+ *
+ * @return the uid of this entry's parent.
+ */
+ public BigInteger getParentID()
+ {
+ return new BigInteger((String) getSingleValue(PARENTID_ATTR)) ;
+ }
+
+
+ /**
+ * Gets the distinguished name of the subschema subentry for this Entry.
+ *
+ * The distinguished name is presumed to be normalized by the server naming
+ * subsystem in accordance with schema attribute syntax and attribute
+ * matching rules. The DN is also presumed to be syntacticly correct and
+ * within the namespace of this directory information base from which this
+ * Entry originated.
+ *
+ * @return String of the subschema subentry distinguished name.
+ */
+ public String getSubschemaSubentryDN()
+ {
+ return (String) getSingleValue(SUBSCHEMASUBENTRY_ATTR) ;
+ }
+
+
+ /**
+ * Checks whether or not this Entry is a valid entry residing within a
+ * backend. Entries are validated on successful create() calls. When
+ * Entry instances are initialized in the java sense via the newEntry()
+ * call on backends, they are in the invalid state.
+ *
+ * @return true if this entry has been persisted to a backend,
+ * false otherwise.
+ */
+ public boolean isValid()
+ {
+ return m_isValid ;
+ }
+
+
+ /**
+ * Gets a multivalued attribute by name.
+ *
+ * @param a_attribName the name of the attribute to lookup.
+ * @return a Collection or null if no attribute value exists.
+ */
+ public Collection getMultiValue(String an_attribName)
+ {
+ return (Collection) get(an_attribName) ;
+ }
+
+
+ /**
+ * Gets a single valued attribute by name or returns the first value of a
+ * multivalued attribute.
+ *
+ * @param a_attribName the name of the attribute to lookup.
+ * @return an Object value which is either a String or byte [] or null if
+ * the attribute does not exist.
+ */
+ public Object getSingleValue(String an_attribName)
+ {
+ Collection l_col = (Collection) get(an_attribName) ;
+
+ if(null == l_col || l_col.isEmpty()) {
+ return null ;
+ }
+
+ return l_col.iterator().next() ;
+ }
+
+
+ private void checkIdentifier( String an_attribName )
+ throws InvalidAttributeIdentifierException
+ {
+ if( ! m_schema.hasAttribute( an_attribName ) )
+ {
+ // InvalidAttributeIdentifierException JNDI exceptions corresponds
+ // to an UNDEFINEDATTRIBUTETYPE result code within LDAPv2 with a
+ // value of [17]
+ throw new InvalidAttributeIdentifierException(
+ "[17] " + an_attribName +
+ " is not a valid schema recognized attribute name." ) ;
+ }
+ }
+
+
+ /**
+ * Adds a value to this Entry potentially resulting in more than one value
+ * for the attribute/key.
+ *
+ * @param an_attribName attribute name/key
+ * @param a_value the value to add
+ * @throws InvalidAttributeIdentifierException when an attempt is made to
+ * add to or create an attribute with an invalid attribute identifier.
+ * @throws InvalidAttributeValueException when an attempt is made to add to
+ * an attribute a value that conflicts with the attribute's schema
+ * definition. This could happen, for example, if attempting to add an
+ * attribute with no value when the attribute is required to have at least
+ * one value, or if attempting to add more than one value to a single
+ * valued-attribute, or if attempting to add a value that conflicts with
+ * the syntax of the attribute.
+ */
+ public void addValue(String an_attribName, Object a_value)
+ throws
+ AttributeInUseException,
+ InvalidAttributeValueException,
+ InvalidAttributeIdentifierException
+ {
+ // Null args have no affect
+ if( null == a_value || null == an_attribName )
+ {
+ return ;
+ }
+
+ checkIdentifier( an_attribName ) ;
+
+ if( containsKey( an_attribName ) &&
+ m_schema.isSingleValue( an_attribName ) )
+ {
+ // AttributeInUseException JNDI exceptions correspond to
+ // ATTRIBUTEORVALUEEXISTS result code in LDAPv3 with a value of [20]
+ throw new AttributeInUseException( "[20] A key for attribute "
+ + an_attribName + " already exists!" ) ;
+ }
+
+
+ // Indices do not exist on binary attributes so there is no need to
+ // update them or for that matter track changes to them
+ if( m_schema.isBinary( an_attribName ) )
+ {
+ put( an_attribName, a_value ) ;
+ }
+
+ // @todo Answer why we are not asking the schema here if the value is
+ // valid when we are dealing with numbers? Shouldn't we be performing
+ // some form of syntax check?
+ else if( m_schema.isNumeric( an_attribName ) ||
+ m_schema.isDecimal( an_attribName ) )
+ {
+ put( an_attribName, a_value ) ;
+
+ if( m_isValid )
+ {
+ m_added.put( an_attribName, a_value ) ;
+ }
+ }
+ else
+ {
+ String l_value = ( String ) a_value ;
+
+ if( l_value.trim().equals( "" ) )
+ {
+ return ;
+ }
+
+ if( ! m_schema.isValidSyntax( an_attribName, l_value ) )
+ {
+ // InvalidAttributeValueException JNDI exceptions correspond to
+ // the INVALIDATTRIBUTESYNTAX result code with a value of [21]
+ throw new InvalidAttributeValueException( "[21] '" + l_value
+ + "' does not comply with the syntax for attribute "
+ + an_attribName ) ;
+ }
+
+ put( an_attribName, l_value ) ;
+
+ if( m_isValid )
+ {
+ m_added.put( an_attribName, l_value ) ;
+ }
+ }
+ }
+
+
+ /**
+ * Removes the attribute/value pair in this Entry only without affecting
+ * other values that the attribute may have.
+ *
+ * @param an_attribName attribute name/key
+ * @param a_value the value to remove
+ * @throws AttributeModificationException when an attempt is made to modify
+ * an attribute, its identifier, or its values that conflicts with the
+ * attribute's (schema) definition or the attribute's state. Also thrown
+ * if the specified attribute name does not exist as a key in this Entry.
+ */
+ public void removeValue( String an_attribName, Object a_value )
+ throws InvalidAttributeIdentifierException
+ {
+ checkIdentifier( an_attribName ) ;
+
+ if( m_schema.isBinary( an_attribName ) )
+ {
+ remove( an_attribName, a_value ) ;
+ }
+ else
+ {
+ remove( an_attribName, a_value ) ;
+
+ // For valid entries within the backend we track what we added and
+ // removed. Need to remove values added to shadow copy that now get
+ // removed.
+ if( m_isValid )
+ {
+ m_removed.put( an_attribName, a_value ) ;
+ m_added.remove( an_attribName, a_value ) ;
+ }
+ }
+ }
+
+
+ /**
+ * Removes all the attribute/value pairs in this Entry associated with the
+ * attribute.
+ *
+ * @param an_attribName attribute name/key
+ * @param a_value the value to remove
+ * @throws AttributeModificationException when an attempt is made to modify
+ * an attribute, its identifier, or its values that conflicts with the
+ * attribute's (schema) definition or the attribute's state. Also thrown
+ * if the specified attribute name does not exist as a key in this Entry.
+ */
+ public void removeValues( String an_attribName )
+ throws InvalidAttributeIdentifierException
+ {
+ checkIdentifier( an_attribName ) ;
+
+ // Don't care if the value does not exist
+ if( ! containsKey( an_attribName ) )
+ {
+ return ;
+ }
+
+ Iterator l_removed = getMultiValue( an_attribName ).iterator() ;
+ if( m_isValid )
+ {
+ while( l_removed.hasNext() )
+ {
+ m_removed.put( an_attribName, l_removed.next() ) ;
+ }
+
+ m_added.remove( an_attribName ) ;
+ }
+
+ remove( an_attribName ) ;
+ }
+
+
+ /**
+ * Removes the specified set of attribute/value pairs in this Entry.
+ *
+ * @param an_attribName attribute name/key
+ * @param a_valueArray the set of values to remove
+ * @throws AttributeModificationException when an attempt is made to modify
+ * an attribute, its identifier, or its values that conflicts with the
+ * attribute's (schema) definition or the attribute's state. Also thrown
+ * if the specified attribute name does not exist as a key in this Entry.
+ */
+ public void removeValues(String an_attribName, Object [] a_valueArray)
+ throws InvalidAttributeIdentifierException
+ {
+ checkIdentifier( an_attribName ) ;
+
+ for( int ii = 0; ii < a_valueArray.length; ii++ )
+ {
+ remove( an_attribName, a_valueArray[ii] ) ;
+ }
+ }
+
+
+ //////////////////////////////
+ // Package Friendly Methods //
+ //////////////////////////////
+
+
+ /**
+ * This method is called to indicate that this entry has now been created
+ * within a backend. Any alterations to be made to is are going to be
+ * tracked using the three multimaps. The add, remove and change methods
+ * will on use now begin to add attribute into the appropriate multimap
+ * resouvoirs to enable store optimization on updates.
+ */
+ void validate()
+ {
+ m_isValid = true ;
+
+ if(null == m_added) {
+ m_added = new MultiHashMap() ;
+ } else {
+ m_added.clear() ;
+ }
+
+ if(null == m_removed) {
+ m_removed = new MultiHashMap() ;
+ } else {
+ m_removed.clear() ;
+ }
+ }
+
+
+ MultiHashMap getRemoved()
+ {
+ return m_removed ;
+ }
+
+
+ MultiHashMap getAdded()
+ {
+ return m_added ;
+ }
+
+
+ /**
+ * Sets the parent id and parent dn operational attributes of this
+ * entry to correspond to a new parent entry. The appropriate changes
+ * are made to the added and removed multimaps to correctly update
+ * this entry with the new parent child relationship. Effects are not
+ * manifested in the backend util an update is performed on this Entry.
+ *
+ * @param a_parentEntry the parent to make this Entry a child of.
+ */
+ void setParent( LdapEntry a_parentEntry )
+ throws NamingException
+ {
+ removeValues( PARENTDN_ATTR ) ;
+ addValue(PARENTDN_ATTR, a_parentEntry.getEntryDN() ) ;
+
+ removeValues( PARENTID_ATTR ) ;
+ addValue( PARENTID_ATTR, ( ( LdapEntryImpl ) a_parentEntry )
+ .getSingleValue( ID_ATTR ) ) ;
+ }
+
+
+ /**
+ * Sets this Entry's DN modifying both the operational attribute for
+ * tracking the user provided DN as well as the normalized DN.
+ *
+ * @param a_dn the new user provided dn to change this Entry's DN to.
+ */
+ void setEntryDN(Name a_dn)
+ throws NamingException
+ {
+ if(getLogger().isDebugEnabled()) {
+ getLogger().debug("" //ProtocolModule.getMessageKey()
+ + " - LdapEntryImpl.setEntryDN() - altering entry dn from "
+ + m_normalizedDn+ " to " + a_dn) ;
+ }
+
+ // Get the old user provided Dn and remove it by removing it from
+ // this MultiMap and adding it to the m_removed MultiMap.
+ String l_oldDn = getEntryDN() ;
+ remove(DN_ATTR, l_oldDn) ;
+ if(m_isValid) {
+ m_removed.put(DN_ATTR, l_oldDn) ;
+ }
+
+ // Reparse as normalized name using schema's normalizing parser
+ m_normalizedDn =
+ m_schema.getNormalizingParser().parse(a_dn.toString()) ;
+
+ // Add unnormalized user provided Dn argument to this MultiMap and
+ // the m_added MultiMap
+ put(DN_ATTR, a_dn.toString()) ;
+ if(this.m_isValid) {
+ m_added.put(DN_ATTR, a_dn.toString()) ;
+ }
+
+ if(getLogger().isDebugEnabled()) {
+ getLogger().debug("" //ProtocolModule.getMessageKey()
+ + " - LdapEntryImpl.setEntryDN() - dumping delta hashes "
+ + "after removing the old dn and adding the new Dn") ;
+ getLogger().debug("Added hash:\n" + this.m_added.toString()) ;
+ getLogger().debug("Removed hash:\n" + this.m_removed.toString()) ;
+ }
+ }
+
+
+ ////////////////////////////////////
+ // Overridden MultiMap Interfaces //
+ ////////////////////////////////////
+
+
+ /**
+ * Gets the user provided key form of the attribute argument first then
+ * calls the super class' containsKey with the calculated UPK. If no
+ * UPK is found then false is returned.
+ */
+ public boolean containsKey(Object a_attrId)
+ {
+ String l_upk = getUserProvidedKey((String) a_attrId) ;
+
+ if(l_upk == null) {
+ return false ;
+ }
+
+ return super.containsKey(l_upk) ;
+ }
+
+
+ /**
+ * Gets the user provided key form of the attribute argument first then
+ * calls the super class' get with the calculated UPK. If no UPK is found
+ * then null is returned.
+ */
+ public Object get(Object a_attrId)
+ {
+ String l_upk = getUserProvidedKey((String) a_attrId) ;
+
+ if(l_upk == null) {
+ return null ;
+ }
+
+ return super.get(l_upk) ;
+ }
+
+
+ /**
+ * Gets the user provided key form of the attribute argument first then
+ * calls the super class' put with the calculated UPK. If there is no
+ * UPK defined it persumes that the argument is the UPK adding it to the
+ * map of canonicial forms to UPKs. So first come first serve - meaning
+ * the first time an attribute is set to a value the text form of the
+ * attribute identifier is set as the UPK.
+ */
+ public Object put(Object a_attrId, Object a_value)
+ {
+ String l_upk = getUserProvidedKey((String) a_attrId) ;
+
+ if(l_upk == null) {
+ setUserProvidedKey((String) a_attrId) ;
+ l_upk = (String) a_attrId ;
+ }
+
+ return super.put(l_upk, a_value) ;
+ }
+
+
+ /**
+ * Gets the user provided key form of the attribute argument first then
+ * calls the super class' remove with the calculated UPK. If no UPK is
+ * found then nothing is done.
+ */
+ public Object remove(Object a_attrId)
+ {
+ String l_upk = getUserProvidedKey((String) a_attrId) ;
+
+ if(l_upk == null) {
+ return null ;
+ }
+
+ return super.remove(l_upk) ;
+ }
+
+
+ /**
+ * Gets the user provided key form of the attribute argument first then
+ * calls the super class' remove with the calculated UPK. If no UPK is
+ * found then nothing is done.
+ */
+ public Object remove(Object a_attrId, Object a_value)
+ {
+ String l_upk = getUserProvidedKey((String) a_attrId) ;
+
+ if(l_upk == null) {
+ return null ;
+ }
+
+ return super.remove(l_upk, a_value) ;
+ }
+
+
+ /////////////////////
+ // Utility Methods //
+ /////////////////////
+
+
+ /**
+ * Gets the canonical text normalized form of the attribute identifier. It
+ * first tests to see if the canonical for exists in the normalized
+ * attribute id cache. If the cannonical form is there it is returned
+ * other wise it generates the normalized form and adds it to the cache.
+ * It then returns this newly generated normalized form.
+ */
+ private String getCanonicalKey(String a_attrId)
+ {
+ String l_canonical = null ;
+
+ // Now if the argument is not the key get the canonical key either
+ // from the attribute id cache or by creating it from scratch.
+ if(m_attrIdCache.containsKey(a_attrId)) {
+ l_canonical = (String) m_attrIdCache.get(a_attrId) ;
+ } else {
+ l_canonical = a_attrId.toLowerCase() ;
+ m_attrIdCache.put(a_attrId, l_canonical) ;
+ m_attrIdCache.put(l_canonical, l_canonical) ;
+ }
+
+ return l_canonical ;
+ }
+
+
+ /**
+ * Gets the original user provided key as was entered into the backend the
+ * first time. It first presumes that the argument a_attrId is already \
+ * normalized by attempting a lookup into the normalized attribute id to
+ * user defined attribute id map. If it finds it there the value is
+ * returned. Otherwise it calls getCanonicalKey on the argument to get
+ * the canonical form and used the cannonical form for the same lookup. If
+ * nothing is found in the id map then null is returned.
+ */
+ private String getUserProvidedKey(String a_attrId)
+ {
+ if(m_attrIdMap.containsKey(a_attrId)) {
+ return (String) m_attrIdMap.get(a_attrId) ;
+ } else {
+ String l_canonical = getCanonicalKey(a_attrId) ;
+ if(m_attrIdMap.containsKey(l_canonical)) {
+ return (String) m_attrIdMap.get(l_canonical) ;
+ }
+ }
+
+ return null ;
+ }
+
+
+ /**
+ * Sets the user defined key in the user defined attribute Id map by making
+ * a call to getCanonicalKey to get the text normalized version of the
+ * argument String a_upk. It uses this normalized form as the key and the
+ * argument String a_upk to create a new entry in the attribute id map.
+ */
+ private void setUserProvidedKey(String a_upk)
+ {
+ String l_canonical = getCanonicalKey(a_upk) ;
+ m_attrIdMap.put(l_canonical, a_upk) ;
+ }
+
+
+ public void enableLogging(Logger a_logger)
+ {
+ m_log = a_logger ;
+ }
+
+
+ public boolean isDebugEnabled()
+ {
+ return m_log.isDebugEnabled() ;
+ }
+
+
+ public Logger getLogger()
+ {
+ return m_log ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/gui/ASTNode.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/gui/ASTNode.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,121 @@
+/*
+ * $Id: ASTNode.java,v 1.2 2003/03/13 18:27:19 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm.gui ;
+
+
+import java.util.ArrayList ;
+import java.util.Enumeration ;
+import javax.swing.tree.TreeNode ;
+
+import org.apache.eve.backend.jdbm.Database ;
+import org.apache.eve.backend.jdbm.LdapEntryImpl ;
+import org.apache.eve.backend.jdbm.index.IndexRecord;
+import java.util.Collections;
+import org.apache.eve.backend.Cursor;
+import java.util.Iterator;
+import org.apache.ldap.common.filter.ExprNode;
+import org.apache.ldap.common.filter.BranchNode;
+import org.apache.ldap.common.filter.LeafNode;
+import org.apache.ldap.common.filter.PresenceNode;
+import org.apache.ldap.common.filter.SubstringNode;
+
+
+/**
+ * A node representing an entry.
+ */
+public class ASTNode
+ implements TreeNode
+{
+ private final ASTNode m_parent ;
+ private final ExprNode m_exprNode ;
+ private final ArrayList m_children ;
+
+
+ public ASTNode(ASTNode a_parent, ExprNode a_exprNode)
+ {
+ m_children = new ArrayList(2) ;
+ m_exprNode = a_exprNode ;
+
+ if(a_parent == null) {
+ m_parent = this ;
+ } else {
+ m_parent = a_parent ;
+ }
+
+ try {
+ if(m_exprNode.isLeaf()) {
+ return ;
+ }
+
+ BranchNode l_branch = (BranchNode) m_exprNode ;
+ ArrayList l_exprNodes = l_branch.getChildren() ;
+ for(int ii = 0 ; ii < l_exprNodes.size(); ii++) {
+ ExprNode l_child = (ExprNode) l_exprNodes.get(ii) ;
+ m_children.add(new ASTNode(this, l_child)) ;
+ }
+ } catch(Exception e) {
+ e.printStackTrace() ;
+ }
+ }
+
+
+ public Enumeration children()
+ {
+ return Collections.enumeration(m_children) ;
+ }
+
+
+ public boolean getAllowsChildren()
+ {
+ return !m_exprNode.isLeaf() ;
+ }
+
+
+ public TreeNode getChildAt(int a_childIndex)
+ {
+ return (TreeNode) m_children.get(a_childIndex) ;
+ }
+
+
+ public int getChildCount()
+ {
+ return m_children.size() ;
+ }
+
+
+ public int getIndex(TreeNode a_child)
+ {
+ return m_children.indexOf(a_child) ;
+ }
+
+
+ public TreeNode getParent()
+ {
+ return m_parent ;
+ }
+
+
+ public boolean isLeaf()
+ {
+ return m_children.size() <= 0 ;
+ }
+
+
+ public String toString()
+ {
+ return m_exprNode.toString() ;
+ }
+
+
+ public ExprNode getExprNode()
+ {
+ return m_exprNode ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/gui/AboutDialog.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/gui/AboutDialog.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,148 @@
+/*
+ * $Id: AboutDialog.java,v 1.2 2003/03/13 18:27:20 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm.gui;
+
+import java.awt.GridBagLayout;
+import java.awt.GridBagConstraints;
+import java.awt.Insets;
+import javax.swing.JPanel;
+import javax.swing.JLabel;
+import javax.swing.JButton;
+import javax.swing.JTextArea;
+import javax.swing.BorderFactory;
+import javax.swing.JDialog;
+import java.awt.Frame;
+import java.awt.Rectangle;
+import java.awt.BorderLayout;
+import java.awt.FlowLayout;
+import java.awt.event.WindowEvent;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+public class AboutDialog extends JDialog {
+ private String title = "About";
+ private String product = "ldapd-modjdbm backend";
+ private String version = "0.7";
+ private String copyright = "Copyright (c) 2003";
+ private String comments =
+ "This is the jdbm backend database viewer or introspector.\n" +
+ "Irregular behavior can be analyzed by using this tool to inspect\n" +
+ "the state of system indices and entry attributes within the backend." ;
+ private JPanel contentPane = new JPanel();
+ private JLabel prodLabel = new JLabel();
+ private JLabel verLabel = new JLabel();
+ private JLabel copLabel = new JLabel();
+ private JTextArea commentField = new JTextArea();
+ private JPanel btnPanel = new JPanel();
+ private JButton okButton = new JButton();
+ private JLabel image = new JLabel();
+ private BorderLayout formLayout = new BorderLayout();
+ private GridBagLayout contentPaneLayout = new GridBagLayout();
+ private FlowLayout btnPaneLayout = new FlowLayout();
+ private JPanel jPanel1 = new JPanel();
+ private JPanel jPanel2 = new JPanel();
+
+ /** Creates new About Dialog */
+ public AboutDialog(Frame parent, boolean modal) {
+ super(parent, modal);
+ initGUI();
+ pack();
+ }
+
+ public AboutDialog() {
+ super();
+ setModal(true);
+ initGUI();
+ pack();
+ }
+
+ /** This method is called from within the constructor to initialize the dialog. */
+ private void initGUI() {
+ addWindowListener(
+ new java.awt.event.WindowAdapter() {
+ public void windowClosing(WindowEvent evt) {
+ closeDialog(evt);
+ }
+ });
+ getContentPane().setLayout(formLayout);
+ contentPane.setLayout(contentPaneLayout);
+ contentPane.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createLineBorder(
+ new java.awt.Color(153, 153, 153), 1), "Ldapd Project", javax.swing.border.TitledBorder.LEADING, javax.swing.border.TitledBorder.TOP,
+ new java.awt.Font("SansSerif", 0, 14), new java.awt.Color(60, 60, 60)));
+ prodLabel.setText(product);
+ prodLabel.setAlignmentX(0.5f);
+ contentPane.add(prodLabel,
+ new java.awt.GridBagConstraints(java.awt.GridBagConstraints.RELATIVE, java.awt.GridBagConstraints.RELATIVE,
+ java.awt.GridBagConstraints.REMAINDER, 1, 0.0, 0.0, java.awt.GridBagConstraints.NORTHWEST, java.awt.GridBagConstraints.NONE,
+ new java.awt.Insets(5, 5, 0, 0), 5, 0));
+ verLabel.setText(version);
+ contentPane.add(verLabel,
+ new java.awt.GridBagConstraints(java.awt.GridBagConstraints.RELATIVE, java.awt.GridBagConstraints.RELATIVE,
+ java.awt.GridBagConstraints.REMAINDER, 1, 0.0, 0.0, java.awt.GridBagConstraints.NORTHWEST, java.awt.GridBagConstraints.NONE,
+ new java.awt.Insets(5, 5, 0, 0), 0, 0));
+ copLabel.setText(copyright);
+ contentPane.add(copLabel,
+ new java.awt.GridBagConstraints(java.awt.GridBagConstraints.RELATIVE, java.awt.GridBagConstraints.RELATIVE,
+ java.awt.GridBagConstraints.REMAINDER, 1, 0.0, 0.0, java.awt.GridBagConstraints.NORTHWEST, java.awt.GridBagConstraints.NONE,
+ new java.awt.Insets(5, 5, 0, 0), 0, 0));
+ commentField.setBackground(getBackground());
+ commentField.setForeground(copLabel.getForeground());
+ commentField.setFont(copLabel.getFont());
+ commentField.setText(comments);
+ commentField.setEditable(false);
+ commentField.setBorder(null);
+ contentPane.add(commentField,
+ new java.awt.GridBagConstraints(java.awt.GridBagConstraints.RELATIVE, java.awt.GridBagConstraints.RELATIVE,
+ java.awt.GridBagConstraints.REMAINDER, 3, 0.0, 1.0, java.awt.GridBagConstraints.NORTHWEST, java.awt.GridBagConstraints.BOTH,
+ new java.awt.Insets(5, 5, 5, 0), 0, 0));
+ image.setText("Ldapd");
+ image.setIcon(
+ new javax.swing.ImageIcon("C:/projects/ldapd-modjdbm/src/java/ldapd/server/backend/modjdbm/gui/ldapd.gif"));
+ image.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING);
+ image.setMinimumSize(new java.awt.Dimension(98,44));
+ image.setMaximumSize(new java.awt.Dimension(98,44));
+ image.setAlignmentX(0.5f);
+ image.setBorder(javax.swing.BorderFactory.createEmptyBorder());
+ image.setPreferredSize(new java.awt.Dimension(98,44));
+ image.setSize(new java.awt.Dimension(98,200));
+ btnPanel.setLayout(btnPaneLayout);
+ okButton.setText("OK");
+ okButton.addActionListener(
+ new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ setVisible(false);
+ dispose();
+ }
+ });
+ btnPanel.add(okButton);
+ getContentPane().add(image, BorderLayout.WEST);
+ getContentPane().add(contentPane, BorderLayout.CENTER);
+ getContentPane().add(btnPanel, BorderLayout.SOUTH);
+ getContentPane().add(jPanel1, java.awt.BorderLayout.NORTH);
+ getContentPane().add(jPanel2, java.awt.BorderLayout.EAST);
+ setTitle(title);
+ setResizable(false);
+ setFont(new java.awt.Font("Dialog",java.awt.Font.BOLD,12));
+ formLayout.setHgap(15);
+ jPanel1.setMinimumSize(new java.awt.Dimension(10, 30));
+ jPanel1.setPreferredSize(new java.awt.Dimension(10, 30));
+ jPanel1.setSize(new java.awt.Dimension(564, 35));
+ jPanel2.setMinimumSize(new java.awt.Dimension(72, 165));
+ jPanel2.setPreferredSize(new java.awt.Dimension(80, 165));
+ jPanel2.setSize(new java.awt.Dimension(72, 170));
+ jPanel2.setMaximumSize(new java.awt.Dimension(80,165));
+ }
+
+ /** Closes the dialog */
+ private void closeDialog(WindowEvent evt) {
+ setVisible(false);
+ dispose();
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/gui/AnnotatedFilterTreeDialog.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/gui/AnnotatedFilterTreeDialog.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,112 @@
+/*
+ * $Id: AnnotatedFilterTreeDialog.java,v 1.2 2003/03/13 18:27:21 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm.gui ;
+
+import javax.swing.JDialog ;
+import java.awt.Frame ;
+import java.awt.event.WindowEvent ;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTree;
+import javax.swing.JTextArea;
+import javax.swing.JButton;
+import javax.swing.tree.TreeModel;
+import java.awt.event.ActionListener;
+import java.awt.event.ActionEvent;
+
+
+public class AnnotatedFilterTreeDialog
+ extends JDialog
+{
+ private JPanel jPanel1 = new JPanel();
+ private JTree jTree1 = new JTree();
+ private JPanel jPanel2 = new JPanel();
+ private JPanel jPanel3 = new JPanel();
+ private JTextArea jTextArea1 = new JTextArea();
+ private JScrollPane jScrollPane1 = new JScrollPane();
+ private JButton jButton1 = new JButton();
+
+ /** Creates new form JDialog */
+ public AnnotatedFilterTreeDialog(Frame parent, boolean modal) {
+ super(parent, modal);
+ initGUI();
+ }
+
+ /** This method is called from within the constructor to initialize the form. */
+ private void initGUI() {
+ addWindowListener(
+ new java.awt.event.WindowAdapter() {
+ public void windowClosing(java.awt.event.WindowEvent evt) {
+ closeDialog(evt);
+ }
+ });
+ pack();
+ getContentPane().setLayout(new java.awt.GridBagLayout());
+ getContentPane().add(jPanel1,
+ new java.awt.GridBagConstraints(0, 0, 1, 1, 1.0, 0.1, java.awt.GridBagConstraints.NORTH, java.awt.GridBagConstraints.BOTH,
+ new java.awt.Insets(10, 5, 5, 5), 0, 0));
+ getContentPane().add(jPanel2,
+ new java.awt.GridBagConstraints(0, 1, 1, 1, 1.0, 0.8, java.awt.GridBagConstraints.CENTER, java.awt.GridBagConstraints.BOTH,
+ new java.awt.Insets(5, 5, 5, 5), 0, 0));
+ getContentPane().add(jPanel3,
+ new java.awt.GridBagConstraints(0, 2, 1, 1, 1.0, 0.1, java.awt.GridBagConstraints.SOUTH, java.awt.GridBagConstraints.HORIZONTAL,
+ new java.awt.Insets(0, 0, 0, 0), 0, 0));
+ jPanel1.setLayout(new java.awt.BorderLayout(10, 10));
+ jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createLineBorder(
+ new java.awt.Color(153, 153, 153), 1), "Search Filter", javax.swing.border.TitledBorder.LEADING, javax.swing.border.TitledBorder.TOP,
+ new java.awt.Font("SansSerif", 0, 14), new java.awt.Color(60, 60, 60)));
+ jPanel1.add(jTextArea1, java.awt.BorderLayout.CENTER);
+ jScrollPane1.getViewport().add(jTree1);
+ jTree1.setBounds(new java.awt.Rectangle(238,142,82,80));
+ jTextArea1.setText("");
+ jTextArea1.setEditable(false);
+ setBounds(new java.awt.Rectangle(0,0,485,414));
+ jPanel2.setLayout(new java.awt.BorderLayout());
+ jPanel2.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createLineBorder(
+ new java.awt.Color(153, 153, 153), 1),
+ "Filter Expression Tree", javax.swing.border.TitledBorder.LEADING, javax.swing.border.TitledBorder.TOP,
+ new java.awt.Font("SansSerif", 0, 14), new java.awt.Color(60, 60, 60)));
+ jPanel2.add(jScrollPane1, java.awt.BorderLayout.CENTER);
+ jButton1.setText("Done");
+ jButton1.setActionCommand("Done");
+ jButton1.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent a_event) {
+ AnnotatedFilterTreeDialog.this.setVisible(false) ;
+ AnnotatedFilterTreeDialog.this.dispose() ;
+ }
+ }) ;
+ jButton1.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
+ jButton1.setAlignmentX(0.5f);
+ jButton1.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
+ jPanel3.setPreferredSize(new java.awt.Dimension(79, 41));
+ jPanel3.setMinimumSize(new java.awt.Dimension(79, 41));
+ jPanel3.setSize(new java.awt.Dimension(471,35));
+ jPanel3.setToolTipText("");
+ jPanel3.add(jButton1);
+ }
+
+ /** Closes the dialog */
+ private void closeDialog(WindowEvent evt) {
+ setVisible(false);
+ dispose();
+ }
+
+
+ public void setModel(TreeModel a_model)
+ {
+ this.jTree1.setModel(a_model) ;
+ }
+
+
+ public void setFilter(String a_filter)
+ {
+ this.jTextArea1.setText(a_filter) ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/gui/BackendFrame.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/gui/BackendFrame.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,742 @@
+/*
+ * $Id: BackendFrame.java,v 1.3 2003/03/13 18:27:22 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm.gui ;
+
+
+import java.io.File ;
+
+import javax.swing.JTree ;
+import javax.swing.JMenu ;
+import javax.swing.JTable ;
+import javax.swing.JFrame ;
+import javax.swing.JPanel ;
+import javax.swing.JLabel ;
+import javax.swing.JMenuBar ;
+import javax.swing.JMenuItem ;
+import javax.swing.JSplitPane ;
+import javax.swing.JSeparator ;
+import javax.swing.JScrollPane ;
+import javax.swing.JTabbedPane ;
+import javax.swing.JFileChooser ;
+import javax.swing.tree.TreePath ;
+import javax.swing.tree.TreeModel ;
+import javax.swing.tree.DefaultTreeModel ;
+import javax.swing.event.TreeSelectionEvent ;
+import javax.swing.event.TreeSelectionListener ;
+
+import java.awt.Dimension ;
+import java.awt.BorderLayout ;
+import java.awt.event.ActionEvent ;
+import java.awt.event.ActionListener ;
+
+import org.apache.eve.backend.jdbm.Database ;
+import org.apache.eve.backend.jdbm.LdapEntryImpl ;
+
+import org.apache.eve.Kernel ;
+import java.util.HashMap;
+import java.awt.Toolkit;
+import org.apache.eve.backend.jdbm.search.SearchEngine;
+import org.apache.eve.backend.jdbm.JdbmModule;
+import org.apache.eve.backend.Backend;
+import org.apache.ldap.common.filter.FilterParserImpl;
+import org.apache.ldap.common.filter.FilterParser;
+import org.apache.ldap.common.filter.ExprNode;
+import org.apache.ldap.common.filter.FilterParserMonitorAdapter;
+
+import javax.swing.JOptionPane;
+import java.util.Iterator;
+import org.apache.eve.backend.jdbm.index.Index;
+import javax.swing.tree.TreeNode;
+import org.apache.eve.backend.jdbm.search.DefaultOptimizer;
+import javax.swing.JTextArea;
+import java.util.Stack;
+import java.math.BigInteger;
+import org.apache.eve.backend.jdbm.index.IndexRecord;
+import javax.swing.table.DefaultTableModel;
+import org.apache.eve.backend.Cursor;
+import org.apache.avalon.framework.logger.LogEnabled;
+import org.apache.avalon.framework.logger.Logger;
+
+
+public class BackendFrame
+ extends JFrame
+ implements LogEnabled
+{
+ private JLabel statusBar = new JLabel("Ready") ;
+ private JPanel m_mainPnl = new JPanel() ;
+ private JSplitPane m_splitPane = new JSplitPane() ;
+ private JTabbedPane m_tabbedPane = new JTabbedPane() ;
+ private JPanel m_entryPnl = new JPanel() ;
+ private JPanel m_idxPnl = new JPanel() ;
+ private JScrollPane m_treePane = new JScrollPane() ;
+ private JTree m_tree = new JTree() ;
+ private JScrollPane m_entryPane = new JScrollPane() ;
+ private JTable m_entryTbl = new JTable() ;
+ private JScrollPane m_idxPane = new JScrollPane() ;
+ private JTable m_idxTbl = new JTable() ;
+ private JMenu m_searchMenu = new JMenu();
+ private JMenuItem m_annotate = new JMenuItem();
+ private JMenuItem m_run = new JMenuItem();
+ private JMenuItem m_debug = new JMenuItem();
+ private JMenu m_indices = new JMenu();
+ private Database m_database = null ;
+ private boolean m_doCleanUp = false ;
+ private HashMap m_nodes = new HashMap() ;
+ private EntryNode m_root = null ;
+ private Kernel m_kernel = null ;
+ private Logger m_logger = null ;
+
+ /**
+ * Creates new form JFrame
+ */
+ public BackendFrame() {
+ initGUI() ;
+ pack() ;
+ }
+
+
+ /**
+ * This method is called from within the constructor to initialize the form
+ */
+ private void initGUI() {
+ m_mainPnl.setBorder(null) ;
+ m_mainPnl.setLayout(new java.awt.BorderLayout()) ;
+ m_mainPnl.add(m_splitPane, java.awt.BorderLayout.CENTER) ;
+ m_splitPane.add(m_tabbedPane, javax.swing.JSplitPane.RIGHT) ;
+ m_splitPane.add(m_treePane, javax.swing.JSplitPane.LEFT) ;
+ m_tabbedPane.add(m_entryPnl, "Entry Attributes") ;
+ m_tabbedPane.add(m_idxPnl, "Entry Indices") ;
+
+ m_entryPnl.setLayout(new java.awt.BorderLayout());
+ m_entryPnl.add(m_entryPane, java.awt.BorderLayout.CENTER);
+
+ m_idxPnl.setLayout(new java.awt.BorderLayout());
+ m_idxPnl.add(m_idxPane, java.awt.BorderLayout.CENTER);
+
+ getContentPane().setLayout(new java.awt.BorderLayout());
+ JPanel content = new JPanel();
+ content.setPreferredSize(new java.awt.Dimension(798, 461));
+ content.setLayout(new java.awt.BorderLayout());
+ content.setBorder(javax.swing.BorderFactory.createEtchedBorder());
+ content.add(m_mainPnl, java.awt.BorderLayout.NORTH);
+ getContentPane().add(content, BorderLayout.CENTER);
+ // set title
+ setTitle("Jdbm DB Backend Viewer");
+ // add status bar
+ getContentPane().add(statusBar, BorderLayout.SOUTH);
+ // add menu bar
+ JMenuBar menuBar = new JMenuBar();
+ JMenu m_backendMenu = new JMenu("File");
+ m_backendMenu.setMnemonic('F');
+ // create Exit menu item
+ JMenuItem m_exit = new JMenuItem("Exit");
+ m_exit.setMnemonic('E');
+ m_exit.setBackground(new java.awt.Color(205,205,205));
+ m_exit.addActionListener(
+ new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ exitForm() ;
+ }
+ });
+ // create About menu item
+ JMenu m_helpMenu = new JMenu("Help");
+ m_helpMenu.setMnemonic('H');
+ JMenuItem m_about = new JMenuItem("About");
+ m_about.setMnemonic('A');
+ m_about.setBackground(new java.awt.Color(205,205,205));
+ m_about.addActionListener(
+ new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ AboutDialog aboutDialog = new AboutDialog (BackendFrame.this, true);
+ Dimension frameSize = getSize();
+ Dimension aboutSize = aboutDialog.getPreferredSize();
+ int x = getLocation().x + (frameSize.width - aboutSize.width) / 2;
+ int y = getLocation().y + (frameSize.height - aboutSize.height) / 2;
+ if (x < 0) x = 0;
+ if (y < 0) y = 0;
+ aboutDialog.setLocation(x, y);
+ aboutDialog.setVisible(true);
+ }
+ });
+ m_helpMenu.setBackground(new java.awt.Color(205,205,205));
+ m_helpMenu.add(m_about);
+ // create Open menu item
+ String l_startPath = null ;
+ if(File.separatorChar == '/') {
+ l_startPath = "../projects/ldapd-test" ;
+ } else {
+ l_startPath = "..\\projects\\ldapd-test" ;
+ }
+
+ final JFileChooser fc = new JFileChooser(l_startPath);
+ JMenuItem m_open = new JMenuItem("Open");
+ m_open.setMnemonic('O');
+ m_open.setName("Open");
+ m_open.setActionCommand("Open");
+ m_open.setBackground(new java.awt.Color(205,205,205));
+ m_open.addActionListener(
+ new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent e) {
+ int returnVal = fc.showOpenDialog(BackendFrame.this);
+ if (returnVal == javax.swing.JFileChooser.APPROVE_OPTION) {
+ File file = fc.getSelectedFile() ;
+ try {
+ loadDatabase("ldapd.test.Harness", file.getParent()) ;
+ } catch(Exception ex) {
+ ex.printStackTrace() ;
+ }
+ } else {
+ // Write your code here what to do if user has canceled Open dialog
+ }
+ }
+ });
+ m_backendMenu.setName("Backend");
+ m_backendMenu.setBackground(new java.awt.Color(205,205,205));
+ m_backendMenu.add(m_open);
+ // create Save menu item
+ // create Print menu item
+ m_backendMenu.add(m_exit);
+ menuBar.setBackground(new java.awt.Color(196,197,203));
+ menuBar.add(m_backendMenu);
+ menuBar.add(m_searchMenu);
+ menuBar.add(m_indices);
+ menuBar.add(m_helpMenu);
+ // sets menu bar
+ setJMenuBar(menuBar);
+ setBounds(new java.awt.Rectangle(0, 0, 802, 515));
+ setSize(new java.awt.Dimension(802,515));
+ setResizable(true);
+ addWindowListener(
+ new java.awt.event.WindowAdapter() {
+ public void windowClosing(java.awt.event.WindowEvent evt) {
+ exitForm() ;
+ }
+ });
+ m_treePane.getViewport().add(m_tree);
+ m_tree.setBounds(new java.awt.Rectangle(6,184,82,80));
+ m_tree.setShowsRootHandles(true);
+ m_tree.setToolTipText("Jdbm DB DIT");
+ m_tree.setScrollsOnExpand(true) ;
+ m_tree.getSelectionModel().addTreeSelectionListener(
+ new TreeSelectionListener() {
+ public void valueChanged(TreeSelectionEvent e) {
+ TreePath l_path = e.getNewLeadSelectionPath() ;
+
+ if(l_path == null) {
+ return ;
+ }
+
+ Object l_last = l_path.getLastPathComponent() ;
+ try {
+ if(l_last instanceof EntryNode) {
+ displayEntry(((EntryNode) l_last).getLdapEntry()) ;
+ }
+ } catch(Exception ex) {
+ ex.printStackTrace() ;
+ }
+ }
+ }) ;
+
+ m_entryPane.getViewport().add(m_entryTbl);
+ m_entryTbl.setBounds(new java.awt.Rectangle(321,103,32,32));
+
+ m_idxPane.getViewport().add(m_idxTbl);
+ m_idxTbl.setBounds(new java.awt.Rectangle(429,134,32,32));
+
+ m_treePane.setSize(new java.awt.Dimension(285, 435));
+ m_treePane.setPreferredSize(new java.awt.Dimension(285, 403));
+ m_searchMenu.setText("Search") ;
+ m_searchMenu.setName("Search") ;
+ m_searchMenu.setBackground(new java.awt.Color(205,205,205));
+ m_searchMenu.add(m_run) ;
+ m_searchMenu.add(m_debug) ;
+ m_searchMenu.add(m_annotate) ;
+
+ ActionListener l_searchHandler = new ActionListener()
+ {
+ public void actionPerformed(ActionEvent an_event) {
+ System.out.println("action command = " + an_event.getActionCommand()) ;
+ doFilterDialog(an_event.getActionCommand()) ;
+ }
+ } ;
+
+ m_annotate.setText(FilterDialog.ANNOTATE_MODE) ;
+ m_annotate.setName(FilterDialog.ANNOTATE_MODE) ;
+ m_annotate.setActionCommand(FilterDialog.ANNOTATE_MODE) ;
+ m_annotate.setBackground(new java.awt.Color(205,205,205));
+ m_annotate.addActionListener(l_searchHandler) ;
+
+ m_run.setText(FilterDialog.RUN_MODE) ;
+ m_run.setName(FilterDialog.RUN_MODE) ;
+ m_run.setActionCommand(FilterDialog.RUN_MODE) ;
+ m_run.setBackground(new java.awt.Color(205,205,205));
+ m_run.addActionListener(l_searchHandler) ;
+
+ m_debug.setText(FilterDialog.DEBUG_MODE) ;
+ m_debug.setName(FilterDialog.DEBUG_MODE) ;
+ m_debug.setActionCommand(FilterDialog.DEBUG_MODE) ;
+ m_debug.setBackground(new java.awt.Color(205,205,205));
+ m_debug.addActionListener(l_searchHandler) ;
+
+ m_indices.setText("Indices") ;
+ m_indices.setName("Indices") ;
+ m_indices.setBackground(new java.awt.Color(205,205,205));
+ }
+
+
+ public void enableLogging(Logger a_logger)
+ {
+ m_logger = a_logger ;
+ }
+
+
+ public void launch()
+ {
+ //Center the frame on screen
+ Dimension l_screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+ Dimension l_frameSize = getSize() ;
+ l_frameSize.height = ((l_frameSize.height > l_screenSize.height)
+ ? l_screenSize.height : l_frameSize.height);
+ l_frameSize.width = ((l_frameSize.width > l_screenSize.width)
+ ? l_screenSize.width : l_frameSize.width);
+ setLocation((l_screenSize.width - l_frameSize.width) / 2,
+ (l_screenSize.height - l_frameSize.height) / 2);
+ setVisible(true) ;
+ }
+
+
+ /**
+ * Exit the Application
+ */
+ private void exitForm() {
+ this.setEnabled(false) ;
+ this.setVisible(false) ;
+ this.dispose() ;
+
+ if(m_doCleanUp && m_database != null) {
+ m_database.sync() ;
+ m_database.close() ;
+ System.exit(0) ;
+ }
+ }
+
+
+ public void doFilterDialog(final String a_mode)
+ {
+ final FilterDialog l_dialog = new FilterDialog(a_mode, this, true) ;
+
+ if(this.m_tree.getSelectionModel().getSelectionPath() != null) {
+ TreePath l_path = m_tree.getSelectionModel().getSelectionPath() ;
+ Object l_last = l_path.getLastPathComponent() ;
+ String l_base = null ;
+ if(l_last instanceof EntryNode) {
+ LdapEntryImpl l_entry = ((EntryNode) l_last).getLdapEntry() ;
+ l_base = l_entry.getEntryDN() ;
+ } else {
+ l_base = m_database.getSuffix().toString() ;
+ }
+
+ l_dialog.setBase(l_base) ;
+ } else {
+ l_dialog.setBase(m_database.getSuffix().toString()) ;
+ }
+
+ l_dialog.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent an_event) {
+ String l_cmd = an_event.getActionCommand() ;
+
+ try {
+ if(l_cmd.equals(FilterDialog.SEARCH_CMD)) {
+ if(a_mode == FilterDialog.RUN_MODE) {
+ doRun(l_dialog.getFilter(), l_dialog.getScope(),
+ l_dialog.getBase(), l_dialog.getLimit()) ;
+ } else if(a_mode == FilterDialog.DEBUG_MODE) {
+ doDebug(l_dialog.getFilter(), l_dialog.getScope(),
+ l_dialog.getBase(), l_dialog.getLimit()) ;
+ } else if(a_mode == FilterDialog.ANNOTATE_MODE) {
+ if(doAnnotate(l_dialog.getFilter())) {
+ // continue
+ } else {
+ // We failed don't loose users filter buf
+ // allow user to make edits.
+ return ;
+ }
+ } else {
+ throw new RuntimeException("Unrecognized mode.") ;
+ }
+ } else if(l_cmd.equals(FilterDialog.CANCEL_CMD)) {
+ // Do nothing! Just exit dialog.
+ } else {
+ throw new
+ RuntimeException("Unrecognized FilterDialog command: "
+ + l_cmd) ;
+ }
+ } catch(Exception e) {
+ e.printStackTrace() ;
+ }
+
+ l_dialog.setVisible(false) ;
+ l_dialog.dispose() ;
+ }
+ }) ;
+
+ //Center the frame on screen
+ l_dialog.setSize(456, 256) ;
+ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+ Dimension frameSize = l_dialog.getSize();
+ frameSize.height = ((frameSize.height > screenSize.height)
+ ? screenSize.height : frameSize.height);
+ frameSize.width = ((frameSize.width > screenSize.width)
+ ? screenSize.width : frameSize.width);
+ l_dialog.setLocation((screenSize.width - frameSize.width) / 2,
+ (screenSize.height - frameSize.height) / 2);
+ l_dialog.setEnabled(true) ;
+ l_dialog.setVisible(true) ;
+ }
+
+
+ public boolean doRun(String a_filter, String a_scope, String a_base,
+ String a_limit)
+ throws Exception
+ {
+ System.out.println("Search attempt using filter '" + a_filter + "' "
+ + "with scope '" + a_scope + "' and a return limit of '" + a_limit
+ + "'") ;
+ SearchEngine l_engine = new SearchEngine() ;
+ l_engine.enableLogging(m_logger) ;
+ FilterParser l_parser = new FilterParserImpl() ;
+ l_parser.setFilterParserMonitor( new FilterParserMonitorAdapter() ) ;
+ ExprNode l_root = null ;
+
+ try {
+ l_root = l_parser.parse(a_filter) ;
+ } catch(Exception e) {
+ JTextArea l_text = new JTextArea() ;
+ String l_msg = e.getMessage() ;
+
+ if(l_msg.length() > 1024) {
+ l_msg = l_msg.substring(0, 1024) + "\n. . . truncated . . ." ;
+ }
+
+ l_text.setText(l_msg) ;
+ l_text.setEnabled(false) ;
+ JOptionPane.showMessageDialog(null, l_text, "Syntax Error",
+ JOptionPane.ERROR_MESSAGE) ;
+ return false ;
+ }
+
+ int l_scope = -1 ;
+
+ if(a_scope == FilterDialog.BASE_SCOPE) {
+ l_scope = Backend.BASE_SCOPE ;
+ } else if(a_scope == FilterDialog.SINGLE_SCOPE) {
+ l_scope = Backend.SINGLE_SCOPE ;
+ } else if(a_scope == FilterDialog.SUBTREE_SCOPE) {
+ l_scope = Backend.SUBTREE_SCOPE ;
+ } else {
+ throw new RuntimeException("Unexpected scope parameter: " +
+ a_scope) ;
+ }
+
+ int l_limit = Integer.MAX_VALUE ;
+ if(!a_limit.equals(FilterDialog.UNLIMITED)) {
+ l_limit = Integer.parseInt(a_limit) ;
+ }
+
+ Cursor l_cursor =
+ l_engine.search(m_database, l_root, a_base, l_scope) ;
+ String [] l_cols = new String [2] ;
+ l_cols[0] = "id" ;
+ l_cols[1] = "dn" ;
+ DefaultTableModel l_tableModel = new DefaultTableModel(l_cols, 0) ;
+ Object [] l_row = new Object[2] ;
+ int l_count = 0 ;
+ while(l_cursor.hasMore() && l_count < l_limit) {
+ IndexRecord l_rec = (IndexRecord) l_cursor.next() ;
+ l_row[0] = l_rec.getEntryId() ;
+ l_row[1] = m_database.getEntryDn((BigInteger) l_row[0]) ;
+ l_tableModel.addRow(l_row) ;
+ l_count++ ;
+ }
+
+ SearchResultDialog l_results = new SearchResultDialog(this, false) ;
+ StringBuffer l_buf = new StringBuffer() ;
+ l_buf.append("base: ").append(a_base).append('\n') ;
+ l_buf.append("scope: ").append(a_scope).append('\n') ;
+ l_buf.append("limit: ").append(a_limit).append('\n') ;
+ l_buf.append("total: ").append(l_count).append('\n') ;
+ l_buf.append("filter:\n").append(a_filter).append('\n') ;
+ l_results.setFilter(l_buf.toString()) ;
+
+ TreeNode l_astRoot = new ASTNode(null, l_root) ;
+ TreeModel l_treeModel = new DefaultTreeModel(l_astRoot, true) ;
+ l_results.setTreeModel(l_treeModel) ;
+ l_results.setTableModel(l_tableModel) ;
+ l_results.setVisible(true) ;
+ return true ;
+ }
+
+
+ public void doDebug(String a_filter, String a_scope, String a_base,
+ String a_limit)
+ {
+ System.out.println("Search attempt using filter '" + a_filter + "' "
+ + "with scope '" + a_scope + "' and a return limit of '" + a_limit
+ + "'") ;
+ }
+
+
+ public void selectTreeNode(BigInteger a_id)
+ {
+ Stack l_stack = new Stack() ;
+ TreeNode l_parent = (EntryNode) m_nodes.get(a_id) ;
+ while(l_parent != null && (l_parent != l_parent.getParent())) {
+ l_stack.push(l_parent) ;
+ l_parent = l_parent.getParent() ;
+ }
+
+
+ Object [] l_comps = null ;
+
+ if(l_stack.size() == 0) {
+ l_comps = new Object[1] ;
+ l_comps[0] = m_root ;
+ } else {
+ l_comps = new Object[l_stack.size()] ;
+ }
+
+ for(int ii = 0; l_stack.size() > 0 && ii < l_comps.length; ii++) {
+ l_comps[ii] = l_stack.pop() ;
+ }
+
+ TreePath l_path = new TreePath(l_comps) ;
+ m_tree.scrollPathToVisible(l_path) ;
+ m_tree.getSelectionModel().setSelectionPath(l_path) ;
+ m_tree.validate() ;
+ }
+
+
+ public boolean doAnnotate(String a_filter)
+ throws Exception
+ {
+ FilterParser l_parser = new FilterParserImpl() ;
+ l_parser.setFilterParserMonitor( new FilterParserMonitorAdapter() );
+ ExprNode l_root = null ;
+
+ try {
+ l_root = l_parser.parse(a_filter) ;
+ } catch(Exception e) {
+ JTextArea l_text = new JTextArea() ;
+ String l_msg = e.getMessage() ;
+
+ if(l_msg.length() > 1024) {
+ l_msg = l_msg.substring(0, 1024) + "\n. . . truncated . . ." ;
+ }
+
+ l_text.setText(l_msg) ;
+ l_text.setEnabled(false) ;
+ JOptionPane.showMessageDialog(null, l_text, "Syntax Error",
+ JOptionPane.ERROR_MESSAGE) ;
+ return false ;
+ }
+
+ AnnotatedFilterTreeDialog l_treeDialog = new
+ AnnotatedFilterTreeDialog(BackendFrame.this, false) ;
+ l_treeDialog.setFilter(a_filter) ;
+
+ DefaultOptimizer l_optimizer = new DefaultOptimizer() ;
+ l_optimizer.annotate(this.m_database, l_root) ;
+ TreeNode l_astRoot = new ASTNode(null, l_root) ;
+ TreeModel l_model = new DefaultTreeModel(l_astRoot, true) ;
+ l_treeDialog.setModel(l_model) ;
+ l_treeDialog.setVisible(true) ;
+ return true ;
+ }
+
+
+ public void showIndexDialog(String a_index)
+ throws Exception
+ {
+ System.out.println("Got request to show index dialog for " + a_index) ;
+ Index l_index = (Index) m_database.getIndex(a_index) ;
+
+ if(l_index != null) {
+ IndexDialog l_dialog = new IndexDialog(this, false, l_index) ;
+ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+ Dimension frameSize = l_dialog.getSize();
+ frameSize.height = ((frameSize.height > screenSize.height)
+ ? screenSize.height : frameSize.height);
+ frameSize.width = ((frameSize.width > screenSize.width)
+ ? screenSize.width : frameSize.width);
+ l_dialog.setLocation((screenSize.width - frameSize.width) / 2,
+ (screenSize.height - frameSize.height) / 2);
+ l_dialog.setEnabled(true) ;
+ l_dialog.setVisible(true) ;
+ }
+ }
+
+
+ public void buildIndicesMenu(Database a_database)
+ {
+ ActionListener l_listener = new ActionListener()
+ {
+ public void actionPerformed(ActionEvent a_event) {
+ try {
+ showIndexDialog(a_event.getActionCommand()) ;
+ } catch(Exception e) {
+ e.printStackTrace() ;
+ }
+ }
+ } ;
+
+ JMenuItem l_item = null ;
+ String [] l_sdi = Database.SYS_INDICES ;
+ Iterator l_udi = a_database.getUDIAttributes() ;
+
+ for(int ii = 0; ii < l_sdi.length; ii++) {
+ l_item = new JMenuItem() ;
+ l_item.setBackground(new java.awt.Color(205,205,205));
+ m_indices.add(l_item) ;
+ l_item.setText(l_sdi[ii]) ;
+ l_item.setName(l_sdi[ii]) ;
+ l_item.setActionCommand(l_sdi[ii]) ;
+ l_item.addActionListener(l_listener) ;
+ }
+
+ m_indices.add(new JSeparator()) ;
+
+ while(l_udi.hasNext()) {
+ String l_index = (String) l_udi.next() ;
+ l_item = new JMenuItem() ;
+ l_item.setBackground(new java.awt.Color(205,205,205));
+ m_indices.add(l_item) ;
+ l_item.setText(l_index) ;
+ l_item.setName(l_index) ;
+ l_item.setActionCommand(l_index) ;
+ l_item.addActionListener(l_listener) ;
+ }
+ }
+
+
+ void displayEntry(LdapEntryImpl a_entry)
+ throws Exception
+ {
+ MultiMapModel l_model = new MultiMapModel(a_entry) ;
+ this.m_entryTbl.setModel(l_model) ;
+
+ if(m_database != null) {
+ l_model = new MultiMapModel(
+ m_database.getIndices(a_entry.getEntryID())) ;
+ this.m_idxTbl.setModel(l_model) ;
+ } else {
+ this.m_idxTbl.setModel(null) ;
+ }
+
+ this.validate() ;
+ }
+
+
+ public void loadDatabase(Database a_database)
+ throws Exception
+ {
+ m_database = a_database ;
+ m_doCleanUp = false ;
+ load() ;
+ }
+
+
+ public void loadDatabase(String a_kernelClass, String a_dirPath)
+ throws Exception
+ {
+ m_doCleanUp = true ;
+
+ m_kernel = (Kernel) Class.forName(a_kernelClass).newInstance() ;
+ m_kernel.setRoot(a_dirPath) ;
+ m_kernel.bootStrap("backend0") ;
+ m_logger = m_kernel.getLogger() ;
+ JdbmModule l_backend = (JdbmModule)
+ m_kernel.getServiceManager().lookup(JdbmModule.ROLE) ;
+ m_database = l_backend.getDatabase() ;
+ load() ;
+ }
+
+
+ private void load()
+ throws Exception
+ {
+ boolean doFiltered = false ;
+ m_nodes = new HashMap() ;
+
+ int l_option =
+ JOptionPane.showConfirmDialog(null, "Would you like to filter "
+ + "leaf nodes on load?", "Use Filter?",
+ JOptionPane.OK_CANCEL_OPTION) ;
+ doFiltered = l_option == JOptionPane.OK_OPTION ;
+
+ if(doFiltered) {
+ SearchEngine l_engine = new SearchEngine() ;
+ final FilterDialog l_dialog =
+ new FilterDialog(FilterDialog.LOAD_MODE, this, true) ;
+ l_dialog.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ l_dialog.setVisible(false) ;
+ l_dialog.dispose() ;
+ }
+ }) ;
+
+ l_dialog.setBase(m_database.getSuffix().toString()) ;
+ l_dialog.setScope(FilterDialog.SUBTREE_SCOPE) ;
+
+ //Center the frame on screen
+ l_dialog.setSize(456, 256) ;
+ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+ Dimension frameSize = l_dialog.getSize();
+ frameSize.height = ((frameSize.height > screenSize.height)
+ ? screenSize.height : frameSize.height);
+ frameSize.width = ((frameSize.width > screenSize.width)
+ ? screenSize.width : frameSize.width);
+ l_dialog.setLocation((screenSize.width - frameSize.width) / 2,
+ (screenSize.height - frameSize.height) / 2);
+ l_dialog.setEnabled(true) ;
+ l_dialog.setVisible(true) ;
+
+ FilterParser l_parser = new FilterParserImpl() ;
+ l_parser.setFilterParserMonitor( new FilterParserMonitorAdapter());
+ ExprNode l_exprNode = l_parser.parse(l_dialog.getFilter()) ;
+
+ int l_scope = -1 ;
+ String l_scopeStr = l_dialog.getScope() ;
+ if(l_scopeStr == FilterDialog.BASE_SCOPE) {
+ l_scope = Backend.BASE_SCOPE ;
+ } else if(l_scopeStr == FilterDialog.SINGLE_SCOPE) {
+ l_scope = Backend.SINGLE_SCOPE ;
+ } else if(l_scopeStr == FilterDialog.SUBTREE_SCOPE) {
+ l_scope = Backend.SUBTREE_SCOPE ;
+ } else {
+ throw new RuntimeException("Unrecognized scope") ;
+ }
+
+ l_exprNode =
+ l_engine.addScopeNode(l_exprNode, l_dialog.getBase(), l_scope) ;
+ m_root = new EntryNode(null, m_database,
+ m_database.getSuffixEntry(), m_nodes, l_exprNode, l_engine) ;
+ } else {
+ m_root = new EntryNode(null, m_database,
+ m_database.getSuffixEntry(), m_nodes) ;
+ }
+
+ DefaultTreeModel l_model = new DefaultTreeModel(m_root) ;
+ m_tree.setModel(l_model) ;
+ buildIndicesMenu(m_database) ;
+ if(this.isVisible()) {
+ m_tree.validate() ;
+ }
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/gui/EntryNode.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/gui/EntryNode.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,172 @@
+/*
+ * $Id: EntryNode.java,v 1.3 2003/03/13 18:27:22 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm.gui ;
+
+
+import java.util.ArrayList ;
+import java.util.Enumeration ;
+import javax.swing.tree.TreeNode ;
+
+import org.apache.eve.backend.jdbm.Database ;
+import org.apache.eve.backend.jdbm.LdapEntryImpl ;
+import org.apache.eve.backend.jdbm.index.IndexRecord;
+import java.util.Collections;
+import org.apache.eve.backend.Cursor;
+import java.util.Iterator;
+import java.util.HashMap;
+import org.apache.ldap.common.filter.ExprNode ;
+import org.apache.eve.backend.jdbm.search.SearchEngine;
+
+
+/**
+ * A node representing an entry.
+ */
+public class EntryNode
+ implements TreeNode
+{
+ private final Database m_db ;
+ private final EntryNode m_parent ;
+ private final LdapEntryImpl m_entry ;
+ private final ArrayList m_children ;
+
+
+ public EntryNode(EntryNode a_parent, Database a_db, LdapEntryImpl a_entry,
+ HashMap a_map)
+ {
+ this(a_parent, a_db, a_entry, a_map, null, null) ;
+ }
+
+
+ public EntryNode(EntryNode a_parent, Database a_db, LdapEntryImpl a_entry,
+ HashMap a_map, ExprNode a_exprNode, SearchEngine a_engine)
+ {
+ m_db = a_db ;
+ m_entry = a_entry ;
+ m_children = new ArrayList() ;
+
+ if(a_parent == null) {
+ m_parent = this ;
+ } else {
+ m_parent = a_parent ;
+ }
+
+ try {
+ ArrayList l_records = new ArrayList() ;
+ Cursor l_cursor = m_db.getChildren(m_entry.getEntryID()) ;
+ while(l_cursor.hasMore()) {
+ IndexRecord l_old = (IndexRecord) l_cursor.next() ;
+ IndexRecord l_new = new IndexRecord() ;
+ l_new.setEntryId(l_old.getEntryId()) ;
+ l_new.setIndexKey(l_old.getIndexKey()) ;
+ l_records.add(l_new) ;
+ }
+ l_cursor.close() ;
+
+ Iterator l_list = l_records.iterator() ;
+ while(l_list.hasNext()) {
+ IndexRecord l_rec = (IndexRecord) l_list.next() ;
+
+ // Avoids root node which is both a parent and child of itself.
+ if(l_rec.getEntryId().equals(m_entry.getEntryID())) {
+ continue ;
+ }
+
+ if(a_engine != null && a_exprNode != null) {
+ if(m_db.getChildCount(l_rec.getEntryId()) == 0) {
+ if(a_engine.assertExpression(m_db, a_exprNode,
+ l_rec.getEntryId()))
+ {
+ LdapEntryImpl l_entry = m_db.read(l_rec.getEntryId()) ;
+ EntryNode l_child =
+ new EntryNode(this, m_db, l_entry, a_map,
+ a_exprNode, a_engine) ;
+ m_children.add(l_child) ;
+ } else {
+ continue ;
+ }
+ } else {
+ LdapEntryImpl l_entry = m_db.read(l_rec.getEntryId()) ;
+ EntryNode l_child = new EntryNode(this, m_db, l_entry,
+ a_map, a_exprNode, a_engine) ;
+ m_children.add(l_child) ;
+ }
+ } else {
+ LdapEntryImpl l_entry = m_db.read(l_rec.getEntryId()) ;
+ EntryNode l_child =
+ new EntryNode(this, m_db, l_entry, a_map) ;
+ m_children.add(l_child) ;
+ }
+ }
+ } catch(Exception e) {
+ e.printStackTrace() ;
+ }
+
+ a_map.put(a_entry.getEntryID(), this) ;
+ }
+
+
+ public Enumeration children()
+ {
+ return Collections.enumeration(m_children) ;
+ }
+
+
+ public boolean getAllowsChildren()
+ {
+ return true ;
+ }
+
+
+ public TreeNode getChildAt(int a_childIndex)
+ {
+ return (TreeNode) m_children.get(a_childIndex) ;
+ }
+
+
+ public int getChildCount()
+ {
+ return m_children.size() ;
+ }
+
+
+ public int getIndex(TreeNode a_child)
+ {
+ return m_children.indexOf(a_child) ;
+ }
+
+
+ public TreeNode getParent()
+ {
+ return m_parent ;
+ }
+
+
+ public boolean isLeaf()
+ {
+ return m_children.size() <= 0 ;
+ }
+
+
+ public String toString()
+ {
+ StringBuffer l_buf = new StringBuffer() ;
+ l_buf.append(m_entry.getEntryDN()) ;
+ if(m_children.size() > 0) {
+ l_buf.append(" [").append(m_children.size()).append(']') ;
+ }
+ return l_buf.toString() ;
+ }
+
+
+ public LdapEntryImpl getLdapEntry()
+ {
+ return m_entry ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/gui/FilterDialog.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/gui/FilterDialog.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,273 @@
+/*
+ * $Id: FilterDialog.java,v 1.2 2003/03/13 18:27:23 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm.gui ;
+
+
+import javax.swing.JLabel ;
+import javax.swing.JFrame ;
+import javax.swing.JPanel ;
+import javax.swing.JDialog ;
+import javax.swing.JButton ;
+import javax.swing.JComboBox ;
+import javax.swing.JTextArea ;
+import javax.swing.JTextField ;
+import javax.swing.BorderFactory ;
+import javax.swing.border.TitledBorder ;
+
+import java.awt.Font ;
+import java.awt.Color ;
+import java.awt.Insets ;
+import java.awt.Dimension ;
+import java.awt.FlowLayout ;
+import java.awt.BorderLayout ;
+import java.awt.GridBagLayout ;
+import java.awt.event.WindowEvent ;
+import java.awt.GridBagConstraints ;
+import java.awt.event.WindowAdapter ;
+import java.awt.event.ActionListener;
+
+import javax.swing.JScrollPane;
+
+
+public class FilterDialog
+ extends JDialog
+{
+ public static final String RUN_MODE = "Run" ;
+ public static final String LOAD_MODE = "Load" ;
+ public static final String DEBUG_MODE = "Debug" ;
+ public static final String ANNOTATE_MODE = "Annotate" ;
+
+ public static final String UNLIMITED = "Unlimited" ;
+
+ public static final String BASE_SCOPE = "Base Object" ;
+ public static final String SINGLE_SCOPE = "Single Level" ;
+ public static final String SUBTREE_SCOPE = "Subtree Level" ;
+
+ public static final String LOAD_CMD = "Load" ;
+ public static final String SEARCH_CMD = "Search" ;
+ public static final String CANCEL_CMD = "Cancel" ;
+
+ private JPanel m_northPnl = new JPanel() ;
+ private JPanel m_centerPnl = new JPanel() ;
+ private JTextArea m_filterText = new JTextArea() ;
+ private JLabel m_scopeLbl = new JLabel() ;
+ private JComboBox m_scopeChoice = new JComboBox() ;
+ private JLabel m_limitLbl = new JLabel() ;
+ private JTextField m_limitField = new JTextField() ;
+ private JPanel m_southPnl = new JPanel() ;
+ private JButton m_searchBut = new JButton() ;
+ private JButton m_cancelBut = new JButton() ;
+ private JScrollPane m_scrollPane = new JScrollPane() ;
+ private final String m_mode ;
+ private JTextField m_baseText = new JTextField();
+ private JPanel m_basePnl = new JPanel();
+ private JLabel jLabel1 = new JLabel();
+
+ /** Creates new form JDialog */
+ public FilterDialog(String a_mode, JFrame parent, boolean modal)
+ {
+ super(parent, modal) ;
+ m_mode = a_mode ;
+ initGUI() ;
+ }
+
+
+ public void addActionListener(ActionListener l_listener)
+ {
+ m_searchBut.addActionListener(l_listener) ;
+ m_cancelBut.addActionListener(l_listener) ;
+ }
+
+
+
+ /**
+ * This method is called from within the constructor to initialize the form
+ */
+ private void initGUI() {
+ m_baseText.setText("");
+ addWindowListener(
+ new WindowAdapter() {
+ public void windowClosing(WindowEvent evt) {
+ closeDialog(evt);
+ }
+ }) ;
+ pack() ;
+
+ getContentPane().setLayout(new java.awt.GridBagLayout()) ;
+ getContentPane().add(m_northPnl,
+ new java.awt.GridBagConstraints(0, 0, 1, 1, 0.9, 0.0, java.awt.GridBagConstraints.NORTH, java.awt.GridBagConstraints.BOTH,
+ new java.awt.Insets(5, 5, 6, 0), 0, 0));
+ getContentPane().add(m_centerPnl,
+ new GridBagConstraints(0, 1, 1, 1, 0.9, 0.9,
+ GridBagConstraints.CENTER, GridBagConstraints.BOTH,
+ new Insets(10, 10, 10, 10), 0, 0));
+ getContentPane().add(m_southPnl,
+ new GridBagConstraints(0, 2, 1, 1, 1.0, 0.0,
+ GridBagConstraints.SOUTH, GridBagConstraints.BOTH,
+ new Insets(0, 0, 2, 0), 0, 0)) ;
+ m_northPnl.setLayout(new GridBagLayout()) ;
+ m_northPnl.setBorder(null) ;
+ m_northPnl.add(m_scopeLbl,
+ new java.awt.GridBagConstraints(0, 0, 1, 1, 0.2, 0.0, java.awt.GridBagConstraints.CENTER, java.awt.GridBagConstraints.NONE,
+ new java.awt.Insets(5, 0, 5, 0), 0, 0));
+ m_northPnl.add(m_scopeChoice,
+ new java.awt.GridBagConstraints(1, 0, 1, 1, 1.0, 0.0, java.awt.GridBagConstraints.CENTER, java.awt.GridBagConstraints.HORIZONTAL,
+ new java.awt.Insets(9, 0, 7, 5), 0, 0));
+ m_northPnl.add(m_limitLbl,
+ new GridBagConstraints(2, 0, 1, 1, 0.0, 0.0,
+ GridBagConstraints.CENTER, GridBagConstraints.NONE,
+ new Insets(5, 10, 5, 5), 0, 0)) ;
+ m_northPnl.add(m_limitField,
+ new java.awt.GridBagConstraints(3, 0, 1, 1, 1.0, 0.0, java.awt.GridBagConstraints.CENTER, java.awt.GridBagConstraints.HORIZONTAL,
+ new java.awt.Insets(11, 0, 9, 10), 0, 0));
+ m_northPnl.add(m_basePnl,
+ new java.awt.GridBagConstraints(0, 1, 4, 1, 0.0, 0.0, java.awt.GridBagConstraints.CENTER, java.awt.GridBagConstraints.BOTH,
+ new java.awt.Insets(5, 10, 5, 10), 0, 0));
+ m_filterText.setText("") ;
+ m_filterText.setBorder(null) ;
+ m_centerPnl.setLayout(new BorderLayout()) ;
+ m_centerPnl.setBorder(BorderFactory.createTitledBorder(
+ BorderFactory.createLineBorder(
+ new Color(153, 153, 153), 1), "Search Filter",
+ TitledBorder.LEADING, TitledBorder.TOP,
+ new Font("SansSerif", 0, 14), new Color(60, 60, 60))) ;
+ m_scrollPane.getViewport().add(m_filterText);
+ m_centerPnl.add(m_scrollPane, BorderLayout.CENTER) ;
+ m_scopeLbl.setText("Scope:") ;
+ m_scopeLbl.setFont(new java.awt.Font("Dialog", java.awt.Font.PLAIN, 14));
+ m_scopeChoice.setSize(new java.awt.Dimension(115, 25));
+ m_scopeChoice.setMaximumSize(new Dimension(32767,25)) ;
+ m_scopeChoice.setMinimumSize(new java.awt.Dimension(115, 25));
+ m_scopeChoice.setPreferredSize(new Dimension(115, 25)) ;
+ m_scopeChoice.addItem(BASE_SCOPE) ;
+ m_scopeChoice.addItem(SINGLE_SCOPE) ;
+ m_scopeChoice.addItem(SUBTREE_SCOPE) ;
+
+ m_limitLbl.setText("Limit:") ;
+ m_limitField.setText("Unlimited") ;
+ m_limitField.setHorizontalAlignment(JTextField.CENTER) ;
+ m_southPnl.setLayout(new FlowLayout(FlowLayout.CENTER, 15, 5)) ;
+ m_southPnl.add(m_searchBut) ;
+
+ if(this.m_mode != LOAD_MODE) {
+ m_searchBut.setText(SEARCH_CMD); ;
+ m_searchBut.setActionCommand(SEARCH_CMD) ;
+ m_southPnl.add(m_cancelBut) ;
+ } else {
+ m_searchBut.setText(LOAD_CMD); ;
+ m_searchBut.setActionCommand(LOAD_CMD) ;
+ }
+
+ m_cancelBut.setText(CANCEL_CMD); ;
+ m_cancelBut.setActionCommand(CANCEL_CMD) ;
+ setBounds(new java.awt.Rectangle(0,0,595,331));
+ m_basePnl.setLayout(new java.awt.GridBagLayout());
+ m_basePnl.add(jLabel1,
+ new java.awt.GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, java.awt.GridBagConstraints.WEST, java.awt.GridBagConstraints.NONE,
+ new java.awt.Insets(0, 0, 0, 0), 0, 0));
+ m_basePnl.add(m_baseText,
+ new java.awt.GridBagConstraints(1, 0, 1, 1, 1.0, 0.0, java.awt.GridBagConstraints.EAST, java.awt.GridBagConstraints.HORIZONTAL,
+ new java.awt.Insets(5, 5, 5, 0), 0, 0));
+ jLabel1.setText("Search Base:");
+ jLabel1.setFont(new java.awt.Font("SansSerif", java.awt.Font.PLAIN, 14));
+
+ if(m_mode == RUN_MODE) {
+ setTitle("Search Filter Dialog: Execute mode") ;
+ } else if(m_mode == LOAD_MODE) {
+ setTitle("Search Filter Dialog: Load mode") ;
+ } else if(m_mode == DEBUG_MODE) {
+ setTitle("Search Filter Dialog: Debug mode") ;
+ } else if(m_mode == ANNOTATE_MODE) {
+ setTitle("Search Filter Dialog: Annotate mode") ;
+ this.m_scopeChoice.setEnabled(false) ;
+ this.m_limitField.setEnabled(false) ;
+ this.m_baseText.setEnabled(false) ;
+ } else {
+ throw new RuntimeException("Unrecognized mode.") ;
+ }
+ }
+
+
+ /**
+ * Closes the dialog
+ */
+ public void closeDialog(WindowEvent evt)
+ {
+ setVisible(false) ;
+ dispose() ;
+ }
+
+
+ public String getScope()
+ {
+ int l_selected = m_scopeChoice.getSelectedIndex() ;
+ return (String) m_scopeChoice.getItemAt(l_selected) ;
+ }
+
+
+ /*
+ public int getScope()
+ {
+ int l_selected = m_scopeChoice.getSelectedIndex() ;
+ String l_scope = (String) m_scopeChoice.getItemAt(l_selected) ;
+
+ if(l_scope == BASE_SCOPE) {
+ return Backend.BASE_SCOPE ;
+ } else if(l_scope == SINGLE_SCOPE) {
+ return Backend.SINGLE_SCOPE ;
+ } else if(l_scope == SUBTREE_SCOPE) {
+ return Backend.SUBTREE_SCOPE ;
+ }
+
+ throw new RuntimeException("Unexpected scope parameter: " + l_scope) ;
+ }
+ */
+
+ public String getLimit()
+ {
+ return m_limitField.getText() ;
+ }
+
+/*
+ public String getLimit()
+ {
+ String l_limit = m_limitField.getText() ;
+
+ if(l_limit.equals(UNLIMITED)) {
+ return -1 ;
+ }
+
+ return Integer.parseInt(l_limit) ;
+ }
+*/
+
+ public String getFilter()
+ {
+ return this.m_filterText.getText() ;
+ }
+
+
+ public void setBase(String a_base)
+ {
+ this.m_baseText.setText(a_base) ;
+ }
+
+
+ public void setScope(String a_scope)
+ {
+ this.m_scopeChoice.setSelectedItem(a_scope) ;
+ }
+
+
+ public String getBase()
+ {
+ return this.m_baseText.getText() ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/gui/IndexDialog.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/gui/IndexDialog.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,256 @@
+/*
+ * $Id: IndexDialog.java,v 1.3 2003/03/13 18:27:24 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+package org.apache.eve.backend.jdbm.gui;
+
+import javax.swing.JDialog;
+import java.awt.Frame;
+import java.awt.Panel;
+import javax.swing.JTabbedPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.table.DefaultTableModel;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JTextField;
+import javax.swing.JComboBox;
+import javax.swing.DefaultComboBoxModel;
+import org.apache.eve.backend.jdbm.index.Index;
+import org.apache.eve.backend.Cursor;
+import javax.swing.JOptionPane;
+import org.apache.regexp.RE;
+import org.apache.eve.backend.jdbm.index.IndexRecord;
+import java.awt.event.ActionListener;
+import java.awt.event.ActionEvent;
+import org.apache.avalon.framework.ExceptionUtil;
+import javax.swing.JTextArea;
+import org.apache.ldap.common.util.StringTools;
+
+public class IndexDialog extends JDialog
+{
+ public static final String DEFAULT_CURSOR = "Default" ;
+ public static final String EQUALITY_CURSOR = "Equality" ;
+ public static final String GREATER_CURSOR = "Greater" ;
+ public static final String LESS_CURSOR = "Less" ;
+ public static final String REGEX_CURSOR = "Regex" ;
+
+ private Panel m_mainPnl = new Panel();
+ private JTabbedPane m_tabbedPane = new JTabbedPane();
+ private JPanel m_listPnl = new JPanel();
+ private JPanel m_cursorPnl = new JPanel();
+ private JPanel m_resultsPnl = new JPanel();
+ private JScrollPane jScrollPane2 = new JScrollPane();
+ private JTable m_resultsTbl = new JTable();
+ private JPanel m_buttonPnl = new JPanel();
+ private JButton m_doneBut = new JButton();
+ private JLabel jLabel1 = new JLabel();
+ private JTextField m_keyText = new JTextField();
+ private JLabel jLabel2 = new JLabel();
+ private JComboBox m_cursorType = new JComboBox();
+ private JButton m_scanBut = new JButton();
+ private Index m_index = null ;
+
+ /** Creates new form JDialog */
+ public IndexDialog(Frame parent, boolean modal, Index a_index)
+ {
+ super(parent, modal) ;
+ m_index = a_index ;
+ initGUI() ;
+ }
+
+ /**
+ * This method is called from within the constructor to initialize the
+ * form.
+ */
+ private void initGUI()
+ {
+ addWindowListener(
+ new java.awt.event.WindowAdapter()
+ {
+ public void windowClosing(java.awt.event.WindowEvent evt)
+ {
+ closeDialog() ;
+ }
+ });
+ pack() ;
+ setTitle("Index On Attribute '" + m_index.getAttribute() + "'") ;
+ setBounds(new java.awt.Rectangle(0, 0, 512, 471));
+ getContentPane().add(m_mainPnl, java.awt.BorderLayout.CENTER);
+ m_mainPnl.setLayout(new java.awt.BorderLayout());
+ m_mainPnl.add(m_tabbedPane, java.awt.BorderLayout.CENTER);
+ m_tabbedPane.add(m_listPnl, "Listing");
+ m_listPnl.setLayout(new java.awt.GridBagLayout());
+ m_listPnl.add(m_cursorPnl,
+ new java.awt.GridBagConstraints(0, 0, 1, 1, 1.0, 0.15, java.awt.GridBagConstraints.NORTH, java.awt.GridBagConstraints.BOTH,
+ new java.awt.Insets(15, 0, 30, 0), 0, 0));
+ m_listPnl.add(m_resultsPnl,
+ new java.awt.GridBagConstraints(0, 1, 1, 1, 1.0, 0.8, java.awt.GridBagConstraints.CENTER, java.awt.GridBagConstraints.BOTH,
+ new java.awt.Insets(0, 0, 0, 0), 0, 0));
+ m_listPnl.add(m_buttonPnl,
+ new java.awt.GridBagConstraints(0, 2, 1, 1, 1.0, 0.05, java.awt.GridBagConstraints.CENTER, java.awt.GridBagConstraints.BOTH,
+ new java.awt.Insets(0, 0, 0, 0), 0, 0));
+ m_cursorPnl.setLayout(new java.awt.GridBagLayout());
+ m_cursorPnl.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createLineBorder(
+ new java.awt.Color(153, 153, 153), 1),
+ "Display Cursor Constraints", javax.swing.border.TitledBorder.LEADING, javax.swing.border.TitledBorder.TOP,
+ new java.awt.Font("SansSerif", 0, 14), new java.awt.Color(60, 60, 60)));
+ m_cursorPnl.add(jLabel1,
+ new java.awt.GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, java.awt.GridBagConstraints.WEST, java.awt.GridBagConstraints.NONE,
+ new java.awt.Insets(0, 15, 0, 10), 0, 0));
+ m_cursorPnl.add(m_keyText,
+ new java.awt.GridBagConstraints(1, 1, 1, 1, 0.4, 0.0, java.awt.GridBagConstraints.WEST, java.awt.GridBagConstraints.BOTH,
+ new java.awt.Insets(5, 5, 5, 236), 0, 0));
+ m_cursorPnl.add(jLabel2,
+ new java.awt.GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, java.awt.GridBagConstraints.WEST, java.awt.GridBagConstraints.NONE,
+ new java.awt.Insets(0, 15, 0, 10), 0, 0));
+ m_cursorPnl.add(m_cursorType,
+ new java.awt.GridBagConstraints(1, 0, 1, 1, 0.4, 0.0, java.awt.GridBagConstraints.WEST, java.awt.GridBagConstraints.NONE,
+ new java.awt.Insets(5, 5, 5, 0), 0, 0));
+ m_resultsPnl.setLayout(new java.awt.BorderLayout());
+ m_resultsPnl.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createLineBorder(
+ new java.awt.Color(153, 153, 153), 1), "Scan Results", javax.swing.border.TitledBorder.LEADING, javax.swing.border.TitledBorder.TOP,
+ new java.awt.Font("SansSerif", 0, 14), new java.awt.Color(60, 60, 60)));
+ m_resultsPnl.add(jScrollPane2, java.awt.BorderLayout.CENTER);
+ jScrollPane2.getViewport().add(m_resultsTbl);
+ m_buttonPnl.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.CENTER, 15, 5));
+ m_buttonPnl.add(m_doneBut);
+ m_buttonPnl.add(m_scanBut);
+ m_doneBut.setText("Done");
+ m_doneBut.setName("Done");
+ m_doneBut.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ closeDialog() ;
+ }
+ }) ;
+
+ jLabel1.setText("Key Constraint:");
+ m_keyText.setText("");
+ m_keyText.setMinimumSize(new java.awt.Dimension(130, 20));
+ m_keyText.setPreferredSize(new java.awt.Dimension(130, 20));
+ m_keyText.setMaximumSize(new java.awt.Dimension(130, 20));
+ m_keyText.setFont(new java.awt.Font("SansSerif", java.awt.Font.PLAIN, 14));
+ m_keyText.setSize(new java.awt.Dimension(130, 20));
+ jLabel2.setText("Cursor Type:");
+ m_cursorType.setMaximumSize(new java.awt.Dimension(32767, 20));
+ m_cursorType.setMinimumSize(new java.awt.Dimension(126, 20));
+ m_cursorType.setPreferredSize(new java.awt.Dimension(130, 20));
+ DefaultComboBoxModel l_comboModel = new DefaultComboBoxModel() ;
+ l_comboModel.addElement(DEFAULT_CURSOR) ;
+ l_comboModel.addElement(EQUALITY_CURSOR) ;
+ l_comboModel.addElement(GREATER_CURSOR) ;
+ l_comboModel.addElement(LESS_CURSOR) ;
+ l_comboModel.addElement(REGEX_CURSOR) ;
+ m_cursorType.setModel(l_comboModel) ;
+ m_cursorType.setMaximumRowCount(5);
+ m_scanBut.setText("Scan");
+ m_scanBut.setName("Scan");
+ m_scanBut.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ doScan(m_keyText.getText(),
+ (String) m_cursorType.getSelectedItem()) ;
+ }
+ }) ;
+
+ doScan(null, DEFAULT_CURSOR) ;
+ }
+
+
+ private void closeDialog()
+ {
+ setVisible(false) ;
+ dispose() ;
+ }
+
+
+ public boolean doScan(String a_key, String a_cursorType)
+ {
+ if(a_key == null || a_key.trim().equals("")) {
+ a_key = null ;
+ }
+
+ if(a_key == null && a_cursorType != DEFAULT_CURSOR) {
+ JOptionPane.showMessageDialog(null, "Cannot use a " +
+ a_cursorType + " cursor type with a null key constraint.",
+ "Missing Key Constraint", JOptionPane.ERROR_MESSAGE) ;
+ return false ;
+ }
+
+ try {
+ Cursor l_cursor = null ;
+
+ if(a_cursorType == EQUALITY_CURSOR) {
+ l_cursor = m_index.getCursor(a_key) ;
+ } else if(a_cursorType == GREATER_CURSOR) {
+ l_cursor = m_index.getCursor(a_key, true) ;
+ } else if(a_cursorType == LESS_CURSOR) {
+ l_cursor = m_index.getCursor(a_key, false) ;
+ } else if(a_cursorType == REGEX_CURSOR) {
+ RE l_regex = StringTools.getRegex(a_key) ;
+ int l_starIndex = a_key.indexOf('*') ;
+
+ if(l_starIndex > 0) {
+ String l_prefix = a_key.substring(0, l_starIndex) ;
+ System.out.println("Regex prefix = " + l_prefix) ;
+ l_cursor = m_index.getCursor(l_regex, l_prefix) ;
+ } else {
+ l_cursor = m_index.getCursor(l_regex) ;
+ }
+ } else {
+ l_cursor = m_index.getCursor() ;
+ }
+
+ Object [] l_cols = new Object [2] ;
+ Object [] l_row = null ;
+ l_cols[0] = "Keys (Attribute Value)" ;
+ l_cols[1] = "Values (Entry Id)" ;
+ DefaultTableModel l_model = new DefaultTableModel(l_cols, 0) ;
+ int l_count = 0 ;
+ while(l_cursor.hasMore()) {
+ IndexRecord l_rec = (IndexRecord) l_cursor.next() ;
+ l_row = new Object [2] ;
+ l_row[0] = l_rec.getIndexKey() ;
+ l_row[1] = l_rec.getEntryId() ;
+ l_model.addRow(l_row) ;
+ l_count++ ;
+ } ;
+
+ m_resultsTbl.setModel(l_model) ;
+ m_resultsPnl.setBorder(
+ javax.swing.BorderFactory.createTitledBorder(
+ javax.swing.BorderFactory.createLineBorder(
+ new java.awt.Color(153, 153, 153), 1),
+ "Scan Results: " + l_count,
+ javax.swing.border.TitledBorder.LEADING,
+ javax.swing.border.TitledBorder.TOP,
+ new java.awt.Font("SansSerif", 0, 14),
+ new java.awt.Color(60, 60, 60))) ;
+
+ if(this.isVisible()) {
+ this.validate() ;
+ }
+ } catch(Exception e) {
+ String l_msg = ExceptionUtil.printStackTrace(e) ;
+ if(l_msg.length() > 1024) {
+ l_msg = l_msg.substring(0, 1024)
+ + "\n. . . TRUNCATED . . ." ;
+ }
+ l_msg = "Error while scanning index "
+ + "on attribute " + m_index.getAttribute() + " using a "
+ + a_cursorType + " cursor type with a key constraint of '"
+ + a_key + "':\n" + l_msg ;
+ JTextArea l_area = new JTextArea() ;
+ l_area.setText(l_msg) ;
+ JOptionPane.showMessageDialog(null, l_area, "Index Scan Error",
+ JOptionPane.ERROR_MESSAGE) ;
+ return false ;
+ }
+
+ return true ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/gui/JdbmBackendViewer.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/gui/JdbmBackendViewer.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,74 @@
+/*
+ * $Id: JdbmBackendViewer.java,v 1.2 2003/03/13 18:27:24 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm.gui ;
+
+import javax.swing.UIManager ;
+import java.awt.Dimension ;
+import java.awt.Toolkit ;
+import java.io.File ;
+import javax.swing.JFileChooser ;
+
+import org.apache.log.Priority;
+import org.apache.log.Hierarchy;
+
+
+public class JdbmBackendViewer
+{
+ public JdbmBackendViewer()
+ {
+ BackendFrame frame = new BackendFrame() ;
+
+ String l_startPath = null ;
+ if(File.separatorChar == '/') {
+ l_startPath = "../projects" ;
+ } else {
+ l_startPath = "..\\projects" ;
+ }
+
+ final JFileChooser fc = new JFileChooser(l_startPath) ;
+ int returnVal = fc.showOpenDialog(frame);
+ if (returnVal == javax.swing.JFileChooser.APPROVE_OPTION) {
+ File file = fc.getSelectedFile() ;
+ try {
+ frame.loadDatabase("ldapd.test.Harness", file.getParent()) ;
+ } catch(Exception ex) {
+ ex.printStackTrace() ;
+ }
+ } else {
+ // Write your code here what to do if user has canceled Open dialog
+ }
+
+ //Center the frame on screen
+ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+ Dimension frameSize = frame.getSize();
+ frameSize.height = ((frameSize.height > screenSize.height)
+ ? screenSize.height : frameSize.height);
+ frameSize.width = ((frameSize.width > screenSize.width)
+ ? screenSize.width : frameSize.width);
+ frame.setLocation((screenSize.width - frameSize.width) / 2,
+ (screenSize.height - frameSize.height) / 2);
+ frame.setVisible(true);
+ System.out.println(frameSize) ;
+ }
+
+
+ public static void main(String[] argv) {
+ // set up system Look&Feel
+ try {
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ }
+ catch (Exception e) {
+ System.out.println("Could not set look and feel to use " +
+ UIManager.getSystemLookAndFeelClassName() + ".") ;
+ //e.printStackTrace() ;
+ }
+ new JdbmBackendViewer ();
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/gui/JdbmTableModel.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/gui/JdbmTableModel.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,73 @@
+/*
+ * $Id: JdbmTableModel.java,v 1.2 2003/03/13 18:27:24 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm.gui ;
+
+
+import java.util.ArrayList ;
+import javax.swing.table.AbstractTableModel ;
+
+
+public class JdbmTableModel
+ extends AbstractTableModel
+{
+ public static final String KEY_COL = "Keys" ;
+ public static final String VAL_COL = "Values" ;
+
+ private ArrayList m_keyList ;
+ private ArrayList m_valList ;
+
+
+ public JdbmTableModel(ArrayList a_keyList, ArrayList a_valList)
+ {
+ this.m_keyList = a_keyList ;
+ this.m_valList = a_valList ;
+ }
+
+
+ public String getColumnName(int a_col)
+ {
+ if(a_col == 0) {
+ return KEY_COL ;
+ } else if(a_col == 1) {
+ return VAL_COL ;
+ } else {
+ throw new RuntimeException("There can only be 2 columns at index "
+ + "0 and at 1") ;
+ }
+ }
+
+
+ public int getRowCount()
+ {
+ return m_keyList.size() ;
+ }
+
+
+ public int getColumnCount()
+ {
+ return 2 ;
+ }
+
+
+ public Object getValueAt(int a_row, int a_col)
+ {
+ if(a_row >= m_keyList.size()) {
+ return("NULL") ;
+ }
+
+ if(this.getColumnName(a_col).equals(KEY_COL)) {
+ return this.m_keyList.get(a_row) ;
+ } else if(this.getColumnName(a_col).equals(VAL_COL)) {
+ return this.m_valList.get(a_row) ;
+ } else {
+ throw new RuntimeException("You did not correctly set col names") ;
+ }
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/gui/MultiMapModel.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/gui/MultiMapModel.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,91 @@
+/*
+ * $Id: MultiMapModel.java,v 1.2 2003/03/13 18:27:24 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm.gui ;
+
+
+import java.util.ArrayList ;
+import javax.swing.table.AbstractTableModel ;
+import org.apache.commons.collections.MultiMap;
+import java.util.Iterator;
+import java.util.Collection;
+
+
+public class MultiMapModel
+ extends AbstractTableModel
+{
+ public static final String KEY_COL = "Keys" ;
+ public static final String VAL_COL = "Values" ;
+
+ private final MultiMap m_map ;
+ private final ArrayList m_keys ;
+ private final int m_rowCount ;
+ private final ArrayList m_vals ;
+
+
+ public MultiMapModel(MultiMap a_map)
+ {
+ this.m_map = a_map ;
+ m_rowCount = m_map.values().size() ;
+ this.m_keys = new ArrayList(m_rowCount) ;
+ this.m_vals = new ArrayList(m_rowCount) ;
+
+ Iterator l_keyList = m_map.keySet().iterator() ;
+ while(l_keyList.hasNext()) {
+ String l_key = (String) l_keyList.next() ;
+ Iterator l_valList = ((Collection) m_map.get(l_key)).iterator() ;
+ while(l_valList.hasNext()) {
+ String l_val = l_valList.next().toString() ;
+ m_keys.add(l_key) ;
+ m_vals.add(l_val) ;
+ }
+ }
+ }
+
+
+ public String getColumnName(int a_col)
+ {
+ if(a_col == 0) {
+ return KEY_COL ;
+ } else if(a_col == 1) {
+ return VAL_COL ;
+ } else {
+ throw new RuntimeException("There can only be 2 columns at index "
+ + "0 and at 1") ;
+ }
+ }
+
+
+ public int getRowCount()
+ {
+ return m_rowCount ;
+ }
+
+
+ public int getColumnCount()
+ {
+ return 2 ;
+ }
+
+
+ public Object getValueAt(int a_row, int a_col)
+ {
+ if(a_row >= m_rowCount) {
+ return("NULL") ;
+ }
+
+ if(this.getColumnName(a_col).equals(KEY_COL)) {
+ return this.m_keys.get(a_row) ;
+ } else if(this.getColumnName(a_col).equals(VAL_COL)) {
+ return this.m_vals.get(a_row) ;
+ } else {
+ throw new RuntimeException("You did not correctly set col names") ;
+ }
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/gui/SearchResultDialog.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/gui/SearchResultDialog.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,158 @@
+/*
+ * $Id: SearchResultDialog.java,v 1.2 2003/03/13 18:27:24 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm.gui ;
+
+import javax.swing.JDialog ;
+import java.awt.Frame ;
+import java.awt.event.WindowEvent ;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTree;
+import javax.swing.JTextArea;
+import javax.swing.JButton;
+import javax.swing.tree.TreeModel;
+import java.awt.event.ActionListener;
+import java.awt.event.ActionEvent;
+import javax.swing.JTable;
+import javax.swing.table.TableModel;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.ListSelectionModel;
+import java.math.BigInteger;
+
+
+public class SearchResultDialog
+ extends JDialog implements ListSelectionListener
+{
+ private JPanel jPanel1 = new JPanel();
+ private JTree jTree1 = new JTree();
+ private JPanel jPanel2 = new JPanel();
+ private JPanel jPanel3 = new JPanel();
+ private JTextArea jTextArea1 = new JTextArea();
+ private JScrollPane jScrollPane1 = new JScrollPane();
+ private JButton jButton1 = new JButton();
+ private JPanel jPanel4 = new JPanel();
+ private JScrollPane jScrollPane2 = new JScrollPane();
+ private JTable m_resultsTbl = new JTable();
+
+ /** Creates new form JDialog */
+ public SearchResultDialog(Frame parent, boolean modal) {
+ super(parent, modal);
+ initGUI();
+ }
+
+ /**
+ * This method is called from within the constructor to initialize the form.
+ */
+ private void initGUI() {
+ addWindowListener(
+ new java.awt.event.WindowAdapter() {
+ public void windowClosing(java.awt.event.WindowEvent evt) {
+ closeDialog(evt);
+ }
+ });
+ pack();
+ getContentPane().setLayout(new java.awt.GridBagLayout());
+ getContentPane().add(jPanel1,
+ new java.awt.GridBagConstraints(0, 0, 1, 1, 1.0, 0.1, java.awt.GridBagConstraints.NORTH, java.awt.GridBagConstraints.BOTH,
+ new java.awt.Insets(10, 5, 5, 5), 0, 0));
+ getContentPane().add(jPanel2,
+ new java.awt.GridBagConstraints(0, 1, 1, 1, 1.0, 0.4, java.awt.GridBagConstraints.CENTER, java.awt.GridBagConstraints.BOTH,
+ new java.awt.Insets(5, 5, 5, 5), 0, 0));
+ getContentPane().add(jPanel3,
+ new java.awt.GridBagConstraints(0, 3, 1, 1, 1.0, 0.1, java.awt.GridBagConstraints.SOUTH, java.awt.GridBagConstraints.BOTH,
+ new java.awt.Insets(0, 0, 0, 0), 0, 0));
+ getContentPane().add(jPanel4,
+ new java.awt.GridBagConstraints(0, 2, 1, 1, 1.0, 0.4, java.awt.GridBagConstraints.CENTER, java.awt.GridBagConstraints.BOTH,
+ new java.awt.Insets(5, 5, 5, 5), 0, 0));
+ jPanel1.setLayout(new java.awt.BorderLayout(10, 10));
+ jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createLineBorder(
+ new java.awt.Color(153, 153, 153), 1), "Specifications", javax.swing.border.TitledBorder.LEADING, javax.swing.border.TitledBorder.TOP,
+ new java.awt.Font("SansSerif", 0, 14), new java.awt.Color(60, 60, 60)));
+ jPanel1.add(jTextArea1, java.awt.BorderLayout.CENTER);
+ jScrollPane1.getViewport().add(jTree1);
+ jTree1.setBounds(new java.awt.Rectangle(238,142,82,80));
+ jTextArea1.setText("");
+ jTextArea1.setEditable(false);
+ setBounds(new java.awt.Rectangle(0, 0, 485, 434));
+ setTitle("Search Results");
+ jPanel2.setLayout(new java.awt.BorderLayout());
+ jPanel2.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createLineBorder(
+ new java.awt.Color(153, 153, 153), 1),
+ "Filter Expression Tree", javax.swing.border.TitledBorder.LEADING, javax.swing.border.TitledBorder.TOP,
+ new java.awt.Font("SansSerif", 0, 14), new java.awt.Color(60, 60, 60)));
+ jPanel2.add(jScrollPane1, java.awt.BorderLayout.CENTER);
+ jButton1.setText("Done");
+ jButton1.setActionCommand("Done");
+ jButton1.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent a_event) {
+ SearchResultDialog.this.setVisible(false) ;
+ SearchResultDialog.this.dispose() ;
+ }
+ }) ;
+ jButton1.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
+ jButton1.setAlignmentX(0.5f);
+ jButton1.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
+ jPanel3.setPreferredSize(new java.awt.Dimension(79, 41));
+ jPanel3.setMinimumSize(new java.awt.Dimension(79, 41));
+ jPanel3.setSize(new java.awt.Dimension(471,35));
+ jPanel3.setToolTipText("");
+ jPanel3.add(jButton1);
+ jPanel4.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createLineBorder(
+ new java.awt.Color(153, 153, 153), 1), "Search Results", javax.swing.border.TitledBorder.LEADING, javax.swing.border.TitledBorder.TOP,
+ new java.awt.Font("SansSerif", 0, 14), new java.awt.Color(60, 60, 60)));
+ jPanel4.setLayout(new java.awt.BorderLayout());
+ jPanel4.add(jScrollPane2, java.awt.BorderLayout.CENTER);
+ jScrollPane2.getViewport().add(m_resultsTbl);
+ m_resultsTbl.setSize(new java.awt.Dimension(450,10));
+ m_resultsTbl.getSelectionModel().addListSelectionListener(this) ;
+ }
+
+
+ public void valueChanged(ListSelectionEvent an_event)
+ {
+ ListSelectionModel l_selectionModel = (ListSelectionModel) an_event.getSource() ;
+ int l_minIndex = l_selectionModel.getMinSelectionIndex() ;
+ int l_maxIndex = l_selectionModel.getMaxSelectionIndex() ;
+
+ for(int ii = l_minIndex ; ii <= l_maxIndex; ii++) {
+ if(l_selectionModel.isSelectedIndex(ii) && !an_event.getValueIsAdjusting()) {
+ BigInteger l_id = (BigInteger)
+ m_resultsTbl.getModel().getValueAt(ii, 0) ;
+ ((BackendFrame) getParent()).selectTreeNode(l_id) ;
+ }
+ }
+ }
+
+
+ /** Closes the dialog */
+ private void closeDialog(WindowEvent evt) {
+ setVisible(false);
+ dispose();
+ }
+
+
+ public void setTreeModel(TreeModel a_model)
+ {
+ this.jTree1.setModel(a_model) ;
+ }
+
+
+ public void setFilter(String a_filter)
+ {
+ this.jTextArea1.setText(a_filter) ;
+ }
+
+
+ public void setTableModel(TableModel a_model)
+ {
+ m_resultsTbl.setModel(a_model) ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/gui/ldapd.gif
==============================================================================
Binary file. No diff available.
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/index/BigIntegerComparator.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/index/BigIntegerComparator.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,47 @@
+/*
+ * $Id: BigIntegerComparator.java,v 1.4 2003/03/13 18:27:25 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm.index ;
+
+
+import java.math.BigInteger ;
+import org.apache.eve.backend.jdbm.table.TableComparator ;
+
+
+public class BigIntegerComparator extends TableComparator
+{
+ /**
+ * Version id for serialization.
+ */
+ final static long serialVersionUID = 1L ;
+
+
+ /**
+ * Compare two objects.
+ *
+ * @param obj1 First object
+ * @param obj2 Second object
+ * @return 1 if obj1 > obj2, 0 if obj1 == obj2, -1 if obj1 < obj2
+ */
+ public int compare( Object an_obj1, Object an_obj2 ) {
+ if (an_obj1 == null) {
+ throw new IllegalArgumentException("Argument 'an_obj1' is null") ;
+ }
+
+ if (an_obj2 == null) {
+ throw new IllegalArgumentException("Argument 'an_obj2' is null") ;
+ }
+
+ //System.out.println("BigIntegerComparator.compare(" + an_obj1 + ", "
+ // + an_obj2 + ")") ;
+ BigInteger l_int1 = (BigInteger) an_obj1 ;
+ BigInteger l_int2 = (BigInteger) an_obj2 ;
+ return l_int1.compareTo(l_int2) ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/index/Index.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/index/Index.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,99 @@
+/*
+ * $Id: Index.java,v 1.6 2003/03/13 18:27:25 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm.index ;
+
+import java.math.BigInteger ;
+import javax.naming.NamingException ;
+
+import org.apache.regexp.RE ;
+
+import org.apache.eve.backend.Cursor ;
+import org.apache.eve.backend.BackendException ;
+
+
+/**
+ * Doc me!
+ * @todo Doc me!
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.6 $
+ */
+public interface Index
+{
+ public String getAttribute() ;
+
+ public String getFilePath() ;
+
+ public int count()
+ throws BackendException, NamingException ;
+
+ public int count(Object an_attrVal)
+ throws BackendException, NamingException ;
+
+ public int count(Object an_attrVal, boolean isGreaterThan)
+ throws BackendException, NamingException ;
+
+ public BigInteger getForward(Object an_attrVal)
+ throws BackendException, NamingException ;
+
+ public Object getReverse(BigInteger a_id)
+ throws BackendException ;
+
+ public void add(Object an_attrVal, BigInteger a_id)
+ throws BackendException, NamingException ;
+
+ public void drop(Object an_attrVal, BigInteger a_id)
+ throws BackendException, NamingException ;
+
+
+ ///////////////////////
+ // Cursor Operations //
+ ///////////////////////
+
+ /*
+ public IndexCursor getReverseCursor()
+ throws BackendException, NamingException ;
+ */
+
+ public IndexCursor getReverseCursor(BigInteger a_id)
+ throws BackendException, NamingException ;
+
+ public IndexCursor getCursor()
+ throws BackendException, NamingException ;
+
+ public IndexCursor getCursor(Object an_attrVal)
+ throws BackendException, NamingException ;
+
+ public IndexCursor getCursor(Object an_attrVal, boolean isGreaterThan)
+ throws BackendException, NamingException ;
+
+ public IndexCursor getCursor(RE a_regex)
+ throws BackendException, NamingException ;
+
+ public IndexCursor getCursor(RE a_regex, String a_prefix)
+ throws BackendException, NamingException ;
+
+ public boolean hasValue(Object an_attrVal, BigInteger a_id)
+ throws BackendException, NamingException ;
+
+ public boolean hasValue(Object an_attrVal, BigInteger a_id,
+ boolean isGreaterThan)
+ throws BackendException, NamingException ;
+
+ public boolean hasValue(RE a_regex, BigInteger a_id)
+ throws BackendException, NamingException ;
+
+ public void close()
+ throws BackendException ;
+
+ public void sync()
+ throws BackendException ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/index/IndexComparator.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/index/IndexComparator.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,110 @@
+/*
+ * $Id: IndexComparator.java,v 1.4 2003/03/13 18:27:26 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm.index ;
+
+
+import org.apache.eve.backend.jdbm.table.TupleComparator ;
+import org.apache.eve.backend.jdbm.table.TableComparator ;
+
+
+/**
+ * Doc me!
+ * @todo Doc me!
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.4 $
+ */
+public class IndexComparator
+ implements TupleComparator
+{
+ public static final StringComparator strComp =
+ new StringComparator() ;
+ public static final BigIntegerComparator intComp =
+ new BigIntegerComparator() ;
+
+ private final boolean isForwardMap ;
+ private final TableComparator m_keyComp ;
+
+
+ public IndexComparator(TableComparator a_keyComp, boolean isForwardMap)
+ {
+ m_keyComp = a_keyComp ;
+ this.isForwardMap = isForwardMap ;
+ }
+
+
+ /**
+ * Gets the comparator used to compare keys. May be null in which
+ * case the compareKey method will throw an UnsupportedOperationException.
+ *
+ * @return the comparator for comparing keys.
+ */
+ public TableComparator getKeyComparator()
+ {
+ if(this.isForwardMap) {
+ return m_keyComp ;
+ }
+
+ return intComp ;
+ }
+
+
+ /**
+ * Gets the binary comparator used to compare valuess. May be null in which
+ * case the compareValue method will throw an UnsupportedOperationException.
+ *
+ * @return the binary comparator for comparing values.
+ */
+ public TableComparator getValueComparator()
+ {
+ if(this.isForwardMap) {
+ return intComp ;
+ }
+
+ return m_keyComp ;
+ }
+
+
+ /**
+ * Compares key Object to determine their sorting order returning a
+ * value = to, < or > than 0.
+ *
+ * @param a_key1 the first key to compare
+ * @param a_key2 the other key to compare to the first
+ * @return 0 if both are equal, a negative value less than 0 if the first
+ * is less than the second, or a postive value if the first is greater than
+ * the second byte array.
+ */
+ public int compareKey(Object a_key1, Object a_key2)
+ {
+ jdbm.helper.Comparator l_comparator =
+ (jdbm.helper.Comparator) getKeyComparator() ;
+ return l_comparator.compare(a_key1, a_key2) ;
+ }
+
+
+ /**
+ * Comparse value Objects to determine their sorting order returning a
+ * value = to, < or > than 0.
+ *
+ * @param a_value1 the first value to compare
+ * @param a_value2 the other value to compare to the first
+ * @return 0 if both are equal, a negative value less than 0 if the first
+ * is less than the second, or a postive value if the first is greater than
+ * the second Object.
+ */
+ public int compareValue(Object a_value1, Object a_value2)
+ {
+ jdbm.helper.Comparator l_comparator =
+ (jdbm.helper.Comparator) getValueComparator() ;
+ return l_comparator.compare(a_value1, a_value2) ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/index/IndexCursor.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/index/IndexCursor.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,106 @@
+/*
+ * $Id: IndexCursor.java,v 1.3 2003/03/13 18:27:26 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm.index ;
+
+
+import org.apache.eve.backend.Cursor ;
+import org.apache.eve.backend.BackendException;
+import javax.naming.NamingException;
+import jdbm.helper.Tuple;
+import org.apache.regexp.RE;
+
+
+public class IndexCursor
+ extends Cursor
+{
+ private final RE m_re ;
+ private final IndexRecord m_tmp = new IndexRecord() ;
+ private final IndexRecord m_returned = new IndexRecord() ;
+ private final IndexRecord m_prefetched = new IndexRecord() ;
+ private final boolean swapKeyVal ;
+ private final Cursor m_cursor ;
+
+
+ IndexCursor(Cursor a_cursor)
+ throws BackendException, NamingException
+ {
+ this(a_cursor, false, null) ;
+ }
+
+
+ IndexCursor(Cursor a_cursor, boolean swapKeyVal)
+ throws BackendException, NamingException
+ {
+ this(a_cursor, swapKeyVal, null) ;
+ }
+
+
+ IndexCursor(Cursor a_cursor, boolean swapKeyVal, RE a_regex)
+ throws BackendException, NamingException
+ {
+ m_re = a_regex ;
+ m_cursor = a_cursor ;
+ this.swapKeyVal = swapKeyVal ;
+
+ if(a_cursor.isClosed()) {
+ super.close() ;
+ return ;
+ }
+
+ prefetch() ;
+ }
+
+
+ private void prefetch()
+ throws BackendException, NamingException
+ {
+ while(m_cursor.hasMore()) {
+ Tuple l_tuple = (Tuple) m_cursor.next() ;
+
+ if(swapKeyVal) {
+ m_tmp.setSwapped(l_tuple) ;
+ } else {
+ m_tmp.setTuple(l_tuple) ;
+ }
+
+ // If regex is null just transfer into prefetched from tmp record
+ // but if it is not then use it to match. Successful match shorts
+ // while loop.
+ if(null == m_re || m_re.match((String) m_tmp.getIndexKey())) {
+ m_prefetched.setIndexKey(m_tmp.getIndexKey()) ;
+ m_prefetched.setEntryId(m_tmp.getEntryId()) ;
+ return ;
+ }
+ }
+
+ // If we got down here then m_cursor has been consumed without a match!
+ close() ;
+ }
+
+
+ protected Object advance()
+ throws BackendException, NamingException
+ {
+ m_returned.setEntryId(m_prefetched.getEntryId()) ;
+ m_returned.setIndexKey(m_prefetched.getIndexKey()) ;
+ prefetch() ;
+ return m_returned ;
+ }
+
+
+ protected boolean canAdvance()
+ throws BackendException, NamingException
+ {
+ return !isClosed() ;
+ }
+
+
+ protected void freeResources() {/*Does nothing*/}
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/index/IndexRecord.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/index/IndexRecord.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,59 @@
+/*
+ * $Id: IndexRecord.java,v 1.3 2003/03/13 18:27:26 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm.index;
+
+
+import jdbm.helper.Tuple ;
+import java.math.BigInteger ;
+
+
+public class IndexRecord
+{
+ private final Tuple m_tuple = new Tuple() ;
+
+
+ public void setTuple(Tuple a_tuple)
+ {
+ m_tuple.setKey(a_tuple.getKey()) ;
+ m_tuple.setValue(a_tuple.getValue()) ;
+ }
+
+
+ public void setSwapped(Tuple a_tuple)
+ {
+ m_tuple.setKey(a_tuple.getValue()) ;
+ m_tuple.setValue(a_tuple.getKey()) ;
+ }
+
+
+ public BigInteger getEntryId()
+ {
+ return (BigInteger) m_tuple.getValue() ;
+ }
+
+
+ public Object getIndexKey()
+ {
+ return m_tuple.getKey() ;
+ }
+
+
+ public void setEntryId(BigInteger a_id)
+ {
+ m_tuple.setValue(a_id) ;
+ }
+
+
+ public void setIndexKey(Object a_key)
+ {
+ m_tuple.setKey(a_key) ;
+ }
+}
+
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/index/JdbmIndex.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/index/JdbmIndex.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,400 @@
+/*
+ * Id: JdbmIndex.java,v 1.10 2003/01/31 04:26:27 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm.index ;
+
+
+import java.io.IOException ;
+import java.io.File ;
+import java.math.BigInteger ;
+import javax.naming.NameParser ;
+import javax.naming.NamingException ;
+
+import org.apache.eve.schema.Schema ;
+import org.apache.eve.backend.Cursor ;
+import org.apache.ldap.common.util.StringTools ;
+import org.apache.eve.schema.Normalizer ;
+import org.apache.ldap.common.NotImplementedException ;
+import org.apache.eve.backend.BackendException ;
+import org.apache.eve.backend.jdbm.table.JdbmTable ;
+import org.apache.eve.backend.jdbm.table.TableComparator ;
+
+import jdbm.recman.RecordManager ;
+
+import org.apache.regexp.RE ;
+import org.apache.commons.collections.LRUMap ;
+import org.apache.avalon.framework.logger.Logger ;
+import org.apache.avalon.framework.ExceptionUtil ;
+import org.apache.avalon.framework.logger.AbstractLogEnabled ;
+
+
+/**
+ * Doc me!
+ * @todo Doc me!
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.12 $
+ */
+public class JdbmIndex
+ extends AbstractLogEnabled
+ implements Index
+{
+ public static final String FORWARD_BTREE = "_forward" ;
+ public static final String REVERSE_BTREE = "_reverse" ;
+
+ private final boolean isString ;
+ private final boolean isDecimal ;
+ private final boolean isInteger ;
+ private final String m_filePath ;
+ private final String m_attribute ;
+ private final Normalizer m_normalizer ;
+
+ private JdbmTable m_forward = null ;
+ private JdbmTable m_reverse = null ;
+ private RecordManager m_recMan = null ;
+ private LRUMap m_keyCache = null ;
+
+
+ public JdbmIndex(String a_attribute, Schema a_schema, String a_wkDirPath)
+ throws BackendException, NamingException
+ {
+ File l_file = new File(a_wkDirPath + File.separator + a_attribute) ;
+ m_filePath = l_file.getAbsolutePath() ;
+ m_attribute = a_attribute ;
+
+ TableComparator l_tableComp = null ;
+
+ if(a_attribute == Schema.DN_ATTR ||
+ a_attribute.equals(Schema.DN_ATTR)) {
+ final NameParser l_parser = a_schema.getNormalizingParser() ;
+ m_normalizer = new Normalizer() {
+ public String getEqualityMatch() {
+ return "distinguishedNameMatch" ;
+ }
+ public String normalize(String a_str)
+ throws NamingException
+ {
+ return l_parser.parse(a_str).toString() ;
+ }
+ } ;
+ this.isDecimal = false ;
+ this.isString = true ;
+ this.isInteger = false ;
+ m_keyCache = new LRUMap(1000) ;
+ l_tableComp = IndexComparator.strComp ;
+ } else if(a_attribute == Schema.EXISTANCE_ATTR ||
+ a_attribute.equals(Schema.EXISTANCE_ATTR)) {
+ m_normalizer = new Normalizer() {
+ public String getEqualityMatch() {
+ return "caseIgnoreMatch" ;
+ }
+ public String normalize(String a_str) {
+ return StringTools.deepTrimToLower(a_str) ;
+ }
+ } ;
+ this.isDecimal = false ;
+ this.isString = true ;
+ this.isInteger = false ;
+ m_keyCache = new LRUMap(1000) ;
+ l_tableComp = IndexComparator.strComp ;
+ } else if(a_attribute == Schema.HIERARCHY_ATTR ||
+ a_attribute.equals(Schema.HIERARCHY_ATTR)) {
+ m_normalizer = new Normalizer() {
+ public String getEqualityMatch() {
+ return "integerMatch" ;
+ }
+ public String normalize(String a_str) {
+ return a_str ;
+ }
+ } ;
+ this.isDecimal = false ;
+ this.isString = false ;
+ this.isInteger = true ;
+ l_tableComp = IndexComparator.intComp ;
+ } else {
+ m_normalizer = a_schema.getNormalizer(m_attribute, true) ;
+ if(a_schema.isDecimal(m_attribute)) {
+ this.isDecimal = true ;
+ this.isInteger = false ;
+ this.isString = false ;
+
+ // We do not have a plan for handling decimal values now!
+ throw new NotImplementedException() ;
+ } else if(a_schema.isNumeric(m_attribute)) {
+ this.isInteger = true ;
+ this.isDecimal = false ;
+ this.isString = false ;
+ l_tableComp = IndexComparator.intComp ;
+ } else if(a_schema.isBinary(m_attribute)) {
+ throw new IllegalArgumentException(
+ "Cannot create an index on binary attribute: '"
+ + m_attribute + "'") ;
+ } else {
+ this.isInteger = false ;
+ this.isDecimal = false ;
+ this.isString = true ;
+ l_tableComp = IndexComparator.strComp ;
+ m_keyCache = new LRUMap(1000) ;
+ }
+ }
+
+ try {
+ m_recMan = new RecordManager(m_filePath) ;
+ m_recMan.disableTransactions() ;
+ } catch(IOException e) {
+ throw new BackendException("Could not initialize the record "
+ + "manager:\n" + ExceptionUtil.printStackTrace(e), e) ;
+ }
+
+ m_forward = new JdbmTable(m_attribute + FORWARD_BTREE,
+ true, m_recMan, new IndexComparator(l_tableComp, true)) ;
+ m_reverse = new JdbmTable(m_attribute + REVERSE_BTREE,
+ true, m_recMan, new IndexComparator(l_tableComp, false)) ;
+ }
+
+
+ public void enableLogging(Logger a_logger)
+ {
+ super.enableLogging(a_logger) ;
+ m_forward.enableLogging(a_logger) ;
+ m_reverse.enableLogging(a_logger) ;
+ }
+
+
+ public String getAttribute()
+ {
+ return m_attribute ;
+ }
+
+
+ public String getFilePath()
+ {
+ return m_filePath ;
+ }
+
+
+ ////////////////////////
+ // Scan Count Methods //
+ ////////////////////////
+
+
+ public int count()
+ throws BackendException, NamingException
+ {
+ return m_forward.count() ;
+ }
+
+
+ public Object getCanonical(Object an_attrVal)
+ throws NamingException
+ {
+ if(this.isString) {
+ String l_canonical = (String) m_keyCache.get(an_attrVal) ;
+
+ if(null == l_canonical) {
+ l_canonical = m_normalizer.normalize((String) an_attrVal) ;
+
+ // Double map it so if we use an already normalized
+ // value we can get back the same normalized value.
+ // and not have to regenerate a second time.
+ m_keyCache.put(an_attrVal, l_canonical) ;
+ m_keyCache.put(l_canonical, l_canonical) ;
+ }
+
+ return l_canonical ;
+ }
+
+ return an_attrVal ;
+ }
+
+
+ public int count(Object an_attrVal)
+ throws BackendException, NamingException
+ {
+ return m_forward.count(getCanonical(an_attrVal)) ;
+ }
+
+
+ public int count(Object an_attrVal, boolean isGreaterThan)
+ throws BackendException, NamingException
+ {
+ return m_forward.count(getCanonical(an_attrVal), isGreaterThan) ;
+ }
+
+
+ /////////////////////////////////
+ // Forward and Reverse Lookups //
+ /////////////////////////////////
+
+
+ public BigInteger getForward(Object an_attrVal)
+ throws BackendException, NamingException
+ {
+ return (BigInteger) m_forward.get(getCanonical(an_attrVal)) ;
+ }
+
+
+ public Object getReverse(BigInteger a_id)
+ throws BackendException
+ {
+ return m_reverse.get(a_id) ;
+ }
+
+
+ //////////////////////
+ // Add/Drop Methods //
+ //////////////////////
+
+
+ public synchronized void add(Object an_attrVal, BigInteger a_id)
+ throws BackendException, NamingException
+ {
+ m_forward.put(getCanonical(an_attrVal), a_id) ;
+ m_reverse.put(a_id, getCanonical(an_attrVal)) ;
+ }
+
+
+ public synchronized void drop(Object an_attrVal, BigInteger a_id)
+ throws BackendException, NamingException
+ {
+ m_forward.remove(getCanonical(an_attrVal), a_id) ;
+ m_reverse.remove(a_id, getCanonical(an_attrVal)) ;
+ }
+
+
+ ///////////////////////
+ // Cursor Operations //
+ ///////////////////////
+
+
+ public IndexCursor getReverseCursor(BigInteger a_id)
+ throws BackendException, NamingException
+ {
+ IndexCursor l_cursor =
+ new IndexCursor(m_reverse.getCursor(a_id), true) ;
+ l_cursor.enableLogging(getLogger()) ;
+ return l_cursor ;
+ }
+
+
+ public IndexCursor getCursor()
+ throws BackendException, NamingException
+ {
+ IndexCursor l_cursor = new IndexCursor(m_forward.getCursor()) ;
+ l_cursor.enableLogging(getLogger()) ;
+ return l_cursor ;
+ }
+
+
+ public IndexCursor getCursor(Object an_attrVal)
+ throws BackendException, NamingException
+ {
+ IndexCursor l_cursor =
+ new IndexCursor(m_forward.getCursor(getCanonical(an_attrVal))) ;
+ l_cursor.enableLogging(getLogger()) ;
+ return l_cursor ;
+ }
+
+
+ public IndexCursor getCursor(Object an_attrVal, boolean isGreaterThan)
+ throws BackendException, NamingException
+ {
+ IndexCursor l_cursor = new IndexCursor(
+ m_forward.getCursor(getCanonical(an_attrVal), isGreaterThan)) ;
+ l_cursor.enableLogging(getLogger()) ;
+ return l_cursor ;
+ }
+
+
+ public IndexCursor getCursor(RE a_regex)
+ throws BackendException, NamingException
+ {
+ IndexCursor l_cursor =
+ new IndexCursor(m_forward.getCursor(), false, a_regex) ;
+ l_cursor.enableLogging(getLogger()) ;
+ return l_cursor ;
+ }
+
+
+ public IndexCursor getCursor(RE a_regex, String a_prefix)
+ throws BackendException, NamingException
+ {
+ IndexCursor l_cursor = new IndexCursor(m_forward.
+ getCursor(getCanonical(a_prefix), true), false, a_regex) ;
+ l_cursor.enableLogging(getLogger()) ;
+ return l_cursor ;
+ }
+
+
+ //////////////////////////////////////////////////
+ // Value Assertion (a.k.a Index Lookup) Methods //
+ //////////////////////////////////////////////////
+
+
+ public boolean hasValue(Object an_attrVal, BigInteger a_id)
+ throws BackendException, NamingException
+ {
+ return m_forward.has(getCanonical(an_attrVal), a_id) ;
+ }
+
+
+ public boolean hasValue(Object an_attrVal, BigInteger a_id,
+ boolean isGreaterThan)
+ throws BackendException, NamingException
+ {
+ return m_forward.has(getCanonical(an_attrVal), a_id, isGreaterThan) ;
+ }
+
+
+ public boolean hasValue(RE a_regex, BigInteger a_id)
+ throws BackendException, NamingException
+ {
+ IndexCursor l_cursor =
+ new IndexCursor(m_reverse.getCursor(a_id), true, a_regex) ;
+ l_cursor.enableLogging(getLogger()) ;
+
+ boolean hasValue = l_cursor.hasMore() ;
+ l_cursor.close() ;
+ return hasValue ;
+ }
+
+
+ /////////////////////////
+ // Maintenance Methods //
+ /////////////////////////
+
+
+ public synchronized void close()
+ throws BackendException
+ {
+ try {
+ m_forward.close() ;
+ m_reverse.close() ;
+ m_recMan.commit() ;
+ m_recMan.close() ;
+ } catch(IOException e) {
+ throw new BackendException("Encountered error while closing "
+ + "backend index file for attribute " + this.m_attribute) ;
+ }
+ }
+
+
+ public synchronized void sync()
+ throws BackendException
+ {
+ try {
+ m_recMan.commit() ;
+ } catch(IOException e) {
+ throw new BackendException("Encountered error while closing "
+ + "backend index file for attribute " + this.m_attribute) ;
+ }
+ }
+}
+
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/index/StringComparator.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/index/StringComparator.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,46 @@
+/*
+ * $Id: StringComparator.java,v 1.2 2003/03/13 18:27:27 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm.index ;
+
+
+import org.apache.eve.backend.jdbm.table.TableComparator ;
+
+
+/**
+ * A StringComparator that is both a java.util.Comparator and a
+ * jdbm.helper.Comparator.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.2 $
+ */
+public class StringComparator extends TableComparator
+{
+ /**
+ * Version id for serialization.
+ */
+ final static long serialVersionUID = 1L ;
+
+
+ /**
+ * Compare two objects.
+ */
+ public int compare( Object a_obj1, Object a_obj2 ) {
+ if (null == a_obj1) {
+ throw new IllegalArgumentException("Argument 'a_obj1' is null") ;
+ }
+
+ if (null == a_obj2) {
+ throw new IllegalArgumentException("Argument 'a_obj2' is null") ;
+ }
+
+ return ((String) a_obj1).compareTo(a_obj2) ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/search/Assertion.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/search/Assertion.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,28 @@
+/*
+ * $Id: Assertion.java,v 1.2 2003/03/13 18:27:28 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm.search ;
+
+
+import javax.naming.NamingException ;
+import org.apache.eve.backend.BackendException ;
+
+
+public interface Assertion
+{
+ /**
+ * Checks to see if a candidate is valid by evaluating an assertion
+ * against the candidate.
+ *
+ * @param a_candidate the candidate to assert
+ * @return true if the candidate is valid, false otherwise
+ */
+ boolean assertCandidate(Object a_candidate)
+ throws BackendException, NamingException ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/search/DefaultOptimizer.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/search/DefaultOptimizer.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,199 @@
+/*
+ * $Id: DefaultOptimizer.java,v 1.2 2003/03/13 18:27:28 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm.search ;
+
+
+import java.util.ArrayList ;
+import java.math.BigInteger ;
+import javax.naming.NamingException ;
+
+import org.apache.eve.schema.Schema ;
+import org.apache.eve.backend.Backend ;
+import org.apache.eve.backend.jdbm.Database ;
+import org.apache.eve.backend.BackendException ;
+
+import org.apache.ldap.common.filter.ExprNode ;
+import org.apache.ldap.common.filter.LeafNode ;
+import org.apache.ldap.common.filter.ScopeNode ;
+import org.apache.ldap.common.filter.SimpleNode ;
+import org.apache.ldap.common.filter.BranchNode ;
+import org.apache.ldap.common.filter.PresenceNode ;
+
+
+/**
+ *
+ */
+public class DefaultOptimizer
+ implements Optimizer
+{
+ public static final BigInteger MAX = BigInteger.valueOf(Integer.MAX_VALUE) ;
+
+ /**
+ * Annotates the expression tree to determine optimal evaluation order based
+ * on the scan count for indices that exist for each expression node. If an
+ * index on the attribute does not exist an IndexNotFoundException will be
+ * thrown.
+ */
+ public void annotate(Database a_db, ExprNode a_node)
+ throws BackendException, NamingException
+ {
+ // Start off with the worst case unless scan count say otherwise.
+ BigInteger l_count = MAX ;
+
+ if ( a_node instanceof ScopeNode )
+ {
+ ScopeNode l_scopeNode = (ScopeNode) a_node ;
+
+ if(l_scopeNode.getScope() == Backend.BASE_SCOPE) {
+ l_count = BigInteger.ONE ;
+ } else if(l_scopeNode.getScope() == Backend.SINGLE_SCOPE) {
+ BigInteger l_id = a_db.getEntryId(l_scopeNode.getBaseDn()) ;
+ l_count = BigInteger.valueOf(a_db.getChildCount(l_id)) ;
+ } else if(l_scopeNode.getScope() == Backend.SUBTREE_SCOPE) {
+ l_count = BigInteger.valueOf(a_db.count()) ;
+ }
+ }
+
+ //////////////////////////////////////////////////////////
+ // H A N D L E L E A F N O D E S //
+ //////////////////////////////////////////////////////////
+
+ // Each assertion leaf node is on an attribute. We ask the index on
+ // that attribute for the scan count representing all the candidates
+ // that would satisfy the assertion.
+ else if(a_node.isLeaf()) {
+ LeafNode l_leaf = (LeafNode) a_node ;
+ switch(l_leaf.getAssertionType()) {
+ case(LeafNode.APPROXIMATE):
+ l_count = BigInteger.valueOf(a_db.getIndexScanCount(
+ l_leaf.getAttribute(),
+ ((SimpleNode) l_leaf).getValue())) ;
+ break ;
+ case(LeafNode.EQUALITY):
+ l_count = BigInteger.valueOf(a_db.getIndexScanCount(
+ l_leaf.getAttribute(),
+ ((SimpleNode) l_leaf).getValue())) ;
+ break ;
+ case(LeafNode.EXTENSIBLE):
+ l_count = BigInteger.valueOf(a_db.getIndexScanCount(
+ l_leaf.getAttribute())) ;
+ break ;
+ case(LeafNode.GREATEREQ):
+ l_count = BigInteger.valueOf(a_db.getIndexScanCount(
+ l_leaf.getAttribute(),
+ ((SimpleNode) l_leaf).getValue(), true)) ;
+ break ;
+ case(LeafNode.LESSEQ):
+ l_count = BigInteger.valueOf(a_db.getIndexScanCount(
+ l_leaf.getAttribute(),
+ ((SimpleNode) l_leaf).getValue(), false)) ;
+ break ;
+ case(LeafNode.PRESENCE):
+ PresenceNode l_presenceNode = (PresenceNode) a_node ;
+ l_count = BigInteger.valueOf(a_db.getIndexScanCount(
+ Schema.EXISTANCE_ATTR,
+ l_presenceNode.getAttribute())) ;
+ break ;
+ case(LeafNode.SUBSTRING):
+ l_count = BigInteger.valueOf(a_db.getIndexScanCount(
+ l_leaf.getAttribute())) ;
+ break ;
+ default:
+ throw new IllegalArgumentException("Unrecognized leaf node") ;
+ }
+
+ //////////////////////////////////////////////////////////
+ // H A N D L E B R A N C H N O D E S //
+ //////////////////////////////////////////////////////////
+
+ } else {
+ ArrayList l_children = null ;
+ BranchNode l_node = (BranchNode) a_node ;
+
+ switch(l_node.getOperator()) {
+ case(BranchNode.AND):
+ //
+ // ANDs or Conjunctions take the count of the smallest child
+ // as their count. This is the best that a conjunction can do
+ // and should be used rather than the worst case. Notice that
+ // we annotate the child node with a recursive call before
+ // accessing its count parameter.
+ //
+ l_count = BigInteger.valueOf(Integer.MAX_VALUE) ;
+ l_children = l_node.getChildren() ;
+ for(int ii = 0; ii < l_children.size(); ii++) {
+ ExprNode l_child = (ExprNode) l_children.get(ii) ;
+ annotate(a_db, l_child) ;
+ l_count =((BigInteger) l_child.get("count")).min(l_count) ;
+ }
+ break ;
+ case(BranchNode.NOT):
+ //
+ // Negation counts are estimated in two ways. First if the
+ // sole child of the negation is a leaf or simple assertion
+ // on an existing index then the count of the negation is set
+ // to the count of all records in the respective index table
+ // as a very rough estimate of the worst possible case.
+ //
+ // If the child is a brach node then the count of the negation
+ // node is set to the total count of entries in the master
+ // table. This tactic is used to get a rough estimate since it
+ // is very costly to estimate the count of a negation over
+ // a compound expression.
+ //
+ ExprNode l_onlyChild = (ExprNode) l_node.getChildren().get(0) ;
+ annotate(a_db, l_onlyChild) ;
+
+ if(l_onlyChild.isLeaf()) {
+ LeafNode l_leaf = (LeafNode) l_onlyChild ;
+ String l_attribute = l_leaf.getAttribute() ;
+
+ if(l_leaf instanceof PresenceNode) {
+ l_count = BigInteger.valueOf(a_db.getIndexScanCount(
+ Schema.EXISTANCE_ATTR)) ;
+ } else {
+ l_count = BigInteger.valueOf(a_db.getIndexScanCount(
+ l_attribute)) ;
+ }
+ } else {
+ l_count = BigInteger.valueOf(a_db.count()) ;
+ }
+
+ break ;
+ case(BranchNode.OR):
+ //
+ // Disjunctions (OR) are the union of candidates across all
+ // subexpressions for this reason we accumulate the counts of
+ // all the child nodes. Notice that we annotate the child node
+ // with a recursive call before accessing its count parameter.
+ //
+ l_children = l_node.getChildren() ;
+ BigInteger l_total = BigInteger.ZERO ;
+ for(int ii = 0; ii < l_children.size(); ii++) {
+ ExprNode l_child = (ExprNode) l_children.get(ii) ;
+ annotate(a_db, l_child) ;
+ l_total = l_total.add((BigInteger) l_child.get("count")) ;
+ }
+
+ l_count = l_total ;
+ break ;
+ default:
+ throw new IllegalArgumentException("Unrecognized branch node") ;
+ }
+ }
+
+ // Protect against overflow when counting.
+ if(l_count.compareTo(BigInteger.ZERO) < 0) {
+ l_count = MAX ;
+ }
+
+ a_node.set("count", l_count) ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/search/DisjunctionCursor.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/search/DisjunctionCursor.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,195 @@
+/*
+ * $Id: DisjunctionCursor.java,v 1.5 2003/05/04 17:46:52 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm.search ;
+
+
+import java.util.Map ;
+import java.util.HashMap ;
+import javax.naming.NamingException ;
+
+import org.apache.eve.backend.Cursor ;
+import org.apache.eve.backend.AtomicBackend ;
+import org.apache.eve.backend.BackendModule ;
+import org.apache.eve.protocol.ProtocolModule ;
+import org.apache.eve.backend.BackendException ;
+import org.apache.eve.backend.jdbm.index.IndexRecord;
+
+
+/**
+ * A Cursor of Cursors performing a union on all underlying Cursors resulting
+ * in the disjunction of expressions represented by the constituant child
+ * Cursors. This cursor prefetches underlying Cursor values so that it can
+ * comply with the defined Cursor semantics.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net"> Alex Karasulu </a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.5 $
+ */
+public class DisjunctionCursor
+ extends Cursor
+{
+ /** The underlying child cursors */
+ private final Cursor [] m_children ;
+ /** LUT used to avoid returning duplicates */
+ private final Map m_candidates = new HashMap() ;
+ /** Index of current cursor used */
+ private int m_index = 0 ;
+ /** Candidate to return */
+ private final IndexRecord m_candidate = new IndexRecord() ;
+ /** Prefetched record returned */
+ private final IndexRecord m_prefetched = new IndexRecord() ;
+
+
+ /**
+ * Creates a DisjunctionCursor over a set of child Cursors. The returned
+ * result is the union of all underlying Cursors without duplicates.
+ *
+ * @param a_backend the owning backend instance
+ * @param a_children array of child Cursors
+ */
+ public DisjunctionCursor(Cursor [] a_children)
+ throws NamingException
+ {
+ m_children = a_children ;
+
+ // Close this cursor if their are no children.
+ if(a_children.length <= 0) {
+ close() ;
+ return ;
+ }
+
+
+ // Advance to the first cursor that has a candidate for us.
+ while(!m_children[m_index].hasMore()) {
+ m_index++ ;
+
+ // Close and return if we exhaust the cursors without finding a
+ // valid candidate to return.
+ if(m_index >= m_children.length) {
+ close() ;
+ return ;
+ }
+ }
+
+ // Grab the next candidate and add it's id to the LUT/hash of candidates
+ IndexRecord l_rec = (IndexRecord) m_children[m_index].next() ;
+ m_prefetched.setEntryId(l_rec.getEntryId()) ;
+ m_prefetched.setIndexKey(l_rec.getIndexKey()) ;
+ m_candidates.put(m_prefetched.getEntryId(), m_prefetched.getEntryId()) ;
+ }
+
+
+ /**
+ * Advances this Cursor one position. Duplicates are not returned so if
+ * underlying cursors keep returning duplicates the child cursors will be
+ * advanced until a unique candidate is found or all child cursors are
+ * exhausted.
+ *
+ * @return a candidate element
+ */
+ public Object advance()
+ throws BackendException, NamingException
+ {
+ // Store the last prefetched candidate to return in m_candidate
+ m_candidate.setEntryId(m_prefetched.getEntryId()) ;
+ m_candidate.setIndexKey(m_prefetched.getIndexKey()) ;
+
+ do {
+ // Advance to a Cursor that has the next valid candidate for us.
+ while(!m_children[m_index].hasMore()) {
+ if(getLogger().isDebugEnabled()) {
+ getLogger().debug("" //ProtocolModule.getMessageKey()
+ + " - DisjunctionCursor.advance(): child cursor "
+ + m_children[m_index] + " at index "
+ + m_index + " has been exhausted.") ;
+ }
+
+ m_index++ ;
+
+ // Close and return existing prefetched candidate if we
+ // have exhausted the underlying Cursors without finding a
+ // valid candidate to return.
+ if(m_index >= m_children.length) {
+ if(getLogger().isDebugEnabled()) {
+ getLogger().debug("" //ProtocolModule.getMessageKey()
+ + " - DisjunctionCursor.advance(): no more child "
+ + "indices left they have all been exhausted. "
+ + "Closing this cursor. Returning last prefetched "
+ + "candidate value of " + m_candidate) ;
+ }
+
+ close() ;
+ return m_candidate ;
+ }
+ }
+
+ // Grab next candidate!
+ IndexRecord l_rec = (IndexRecord) m_children[m_index].next() ;
+ m_prefetched.setIndexKey(l_rec.getIndexKey()) ;
+ m_prefetched.setEntryId(l_rec.getEntryId()) ;
+
+ if(getLogger().isDebugEnabled()) {
+ getLogger().debug("" //ProtocolModule.getMessageKey()
+ + " - DisjunctionCursor.advance(): got next prefetched "
+ + "candidate value of " + m_prefetched.getEntryId()
+ + " Did we see it before? "
+ + m_candidates.containsKey(m_prefetched.getEntryId())) ;
+ }
+
+ // Break through do/while if the candidate is seen for the first
+ // time, meaning we have not returned it already.
+ } while(m_candidates.containsKey(m_prefetched.getEntryId())) ;
+
+ if(getLogger().isDebugEnabled()) {
+ getLogger().debug("" //ProtocolModule.getMessageKey()
+ + " - DisjunctionCursor.advance(): got next valid candidate "
+ + "with a value of " + m_prefetched.getEntryId()
+ + ". Returning last "
+ + "prefetched value of " + m_candidate.getEntryId()) ;
+ }
+
+ // Add candidate to LUT of encountered candidates.
+ m_candidates.put(m_candidate.getEntryId(), m_candidate.getEntryId()) ;
+
+ // Return the original prefetched value
+ return m_candidate ;
+ }
+
+
+ /**
+ * Tests if a prefetched value exists and a call to advance will hence
+ * succeed.
+ *
+ * @return true if a call to advance will succeed false otherwise.
+ */
+ public boolean canAdvance()
+ throws BackendException, NamingException
+ {
+ return !isClosed() ;
+ }
+
+
+ /**
+ * Closes all the underlying Cursors.
+ */
+ public void freeResources()
+ {
+ for(int ii = 0; ii < m_children.length; ii++) {
+ // Close all children but don't fail fast meaning don't stop
+ // closing all children if one fails to close for some reason.
+ try {
+ m_children[ii].close() ;
+ } catch(Throwable t) {
+ getLogger().warn("Could not close underlying cursor " +
+ m_children[ii], t) ;
+ }
+ }
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/search/Optimizer.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/search/Optimizer.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,32 @@
+/*
+ * $Id: Optimizer.java,v 1.2 2003/03/13 18:27:29 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm.search ;
+
+
+import javax.naming.NamingException ;
+
+import org.apache.ldap.common.filter.ExprNode ;
+import org.apache.eve.backend.jdbm.Database ;
+import org.apache.eve.backend.BackendException ;
+
+
+/**
+ * An optimizer applies heuristics to determine best execution path to a search
+ * filter based on scan counts within database indices. It annotates the nodes
+ * of an expression subtree by setting a "count" key in the node. Its goal is
+ * to annotate nodes with counts to indicate which nodes to iterate over thereby
+ * minimizing the number cycles in a search. The SearchEngine relies on these
+ * count markers to determine the appropriate path.
+ */
+public interface Optimizer
+{
+ public void annotate(Database a_db, ExprNode a_node)
+ throws BackendException, NamingException ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/search/PrefetchCursor.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/search/PrefetchCursor.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,185 @@
+/*
+ * $Id: PrefetchCursor.java,v 1.3 2003/03/13 18:27:29 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm.search ;
+
+
+import java.util.Map ;
+import java.util.HashMap ;
+import java.util.ArrayList ;
+
+import java.math.BigInteger ;
+import javax.naming.NamingException ;
+
+import org.apache.eve.backend.Cursor ;
+import org.apache.ldap.common.filter.ExprNode ;
+import org.apache.eve.backend.jdbm.JdbmDatabase ;
+import org.apache.eve.protocol.ProtocolModule ;
+import org.apache.eve.backend.BackendException ;
+import org.apache.eve.backend.jdbm.search.Assertion ;
+import org.apache.eve.backend.jdbm.index.IndexRecord ;
+
+
+/**
+ * A LogicalCursor represents a Cursor over wither a AND/NOT/OR expression in a
+ * filter. This cursor prefetches underlying Cursor values so that it can comply
+ * with the defined Cursor semantics.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net"> Alex Karasulu </a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.3 $
+ */
+public class PrefetchCursor
+ extends Cursor
+{
+ /** The prefetched candidate */
+ private final IndexRecord m_prefetched = new IndexRecord() ;
+ /** The returned candidate */
+ private final IndexRecord m_candidate = new IndexRecord() ;
+ /** The iteration cursor */
+ private final Cursor m_cursor ;
+ /** LUT used to avoid returning duplicates */
+ private final Map m_candidates ;
+ private final Assertion m_assertion ;
+ private final boolean checkDups ;
+
+
+ /**
+ * Cursor over a conjunction expression. All children except the candidate
+ * child to be used for iteration are provided as expressions. The child
+ * cursor is the basis for the iteration.
+ *
+ * @param a_backend the owning backend instance
+ * @param a_cursor underlying iteration cursor
+ * @param a_assertions array of assertions minus the assertion expression
+ * used to construct this cursor.
+ */
+ public PrefetchCursor(Cursor a_cursor, Assertion a_assertion)
+ throws BackendException, NamingException
+ {
+ m_cursor = a_cursor ;
+ m_candidates = null ;
+ m_assertion = a_assertion ;
+ checkDups = false ;
+ prefetch() ;
+ }
+
+
+ public PrefetchCursor(Cursor a_cursor,
+ Assertion a_assertion, boolean enableDupCheck)
+ throws BackendException, NamingException
+ {
+ m_cursor = a_cursor ;
+ m_candidates = new HashMap() ;
+ m_assertion = a_assertion ;
+ checkDups = true ;
+ prefetch() ;
+ }
+
+
+ /**
+ * Checks to see is a candidate is valid by evaluation all assertions
+ * against the candidate. Any assertion failure short circuts tests
+ * returning false. Success through all assertions returns true.
+ *
+ * @param a_candidate the candidate to assert
+ * @return true if the candidate is valid, false otherwise
+ * @throws ClassCastException if the candidate is not a BigInteger.
+ */
+ protected boolean assertCandidate(Object a_candidate)
+ throws BackendException, NamingException
+ {
+ return m_assertion.assertCandidate(a_candidate) ;
+ }
+
+
+ /**
+ * Advances this Cursor one position. Underlying Cursor may be advanced
+ * several possitions while trying to find the next prefetched candidate to
+ * return. If underlying Cursor elements are not valid meaning they do not
+ * pass assertions then they are rejected for return and the next item is
+ * tested. If the underlying Cursor is consumed, then the last prefetched
+ * value is returned and this Cursor is closed.
+ *
+ * @return a valid candidate element that passed all assertions.
+ */
+ public Object advance()
+ throws BackendException, NamingException
+ {
+ m_candidate.setEntryId(m_prefetched.getEntryId()) ;
+ m_candidate.setIndexKey(m_prefetched.getIndexKey()) ;
+ prefetch() ;
+ return m_candidate ;
+ }
+
+
+ private void prefetch()
+ throws BackendException, NamingException
+ {
+ IndexRecord l_rec = null ;
+
+ // Scan underlying Cursor until we arrive at the next valid candidate
+ // if the cursor is exhuasted we clean up after completing the loop
+ while(m_cursor.hasMore()) {
+ l_rec = (IndexRecord) m_cursor.next() ;
+
+ // If value is valid then we set it as the next candidate to return
+ if(assertCandidate(l_rec)) {
+ // dup checking is on but candidate is not in already seen LUT
+ // so we need to set it as next to return and add it to the LUT
+ if(checkDups && !m_candidates.containsKey(l_rec.getEntryId())) {
+ m_prefetched.setEntryId(l_rec.getEntryId()) ;
+ m_prefetched.setIndexKey(l_rec.getIndexKey()) ;
+ m_candidates.put(l_rec.getEntryId(), l_rec.getEntryId()) ;
+ return ;
+ // dup checking is on and candidate has already been seen so we
+ // need to skip it.
+ } else if(checkDups &&
+ m_candidates.containsKey(l_rec.getEntryId()))
+ {
+ continue ;
+ }
+
+ m_prefetched.setEntryId(l_rec.getEntryId()) ;
+ m_prefetched.setIndexKey(l_rec.getIndexKey()) ;
+ return ;
+ }
+ }
+
+ // At this pt the underlying Cursor has been exhaused so we close up
+ // and set the prefetched value to null so canAdvance returns false.
+ close() ;
+ }
+
+
+ /**
+ * Tests if a prefetched value exists and a call to advance will hence
+ * succeed.
+ *
+ * @return true if a call to advance will succeed false otherwise.
+ */
+ public boolean canAdvance()
+ throws BackendException, NamingException
+ {
+ return !isClosed() ;
+ }
+
+
+ /**
+ * Closes the underlying Cursor.
+ */
+ public void freeResources()
+ {
+ try {
+ m_cursor.close() ;
+ } catch(NamingException e) {
+ getLogger().warn("Could not close conjunction cursor child", e) ;
+ }
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/search/SearchEngine.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/search/SearchEngine.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,493 @@
+/*
+ * $Id: SearchEngine.java,v 1.5.4.1 2003/10/01 03:37:55 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm.search ;
+
+
+import java.util.Iterator ;
+import java.util.ArrayList ;
+import java.math.BigInteger ;
+import javax.naming.NamingException ;
+
+
+import org.apache.eve.schema.Schema ;
+import org.apache.eve.backend.Cursor ;
+import org.apache.eve.backend.Backend ;
+import org.apache.ldap.common.filter.ExprNode ;
+import org.apache.ldap.common.filter.LeafNode ;
+import org.apache.ldap.common.filter.ScopeNode ;
+import org.apache.ldap.common.filter.SimpleNode ;
+import org.apache.ldap.common.filter.BranchNode ;
+import org.apache.ldap.common.filter.PresenceNode ;
+import org.apache.ldap.common.filter.SubstringNode ;
+import org.apache.eve.backend.jdbm.Database ;
+import org.apache.ldap.common.NotImplementedException ;
+import org.apache.ldap.common.message.DerefAliasesEnum;
+import org.apache.eve.backend.BackendException ;
+import org.apache.eve.backend.jdbm.index.Index ;
+import org.apache.eve.backend.jdbm.index.IndexRecord ;
+
+
+import org.apache.avalon.framework.logger.AbstractLogEnabled ;
+
+import org.apache.regexp.RE ;
+import org.apache.regexp.RESyntaxException ;
+
+
+/**
+ * Given a search filter and a scope the search engine identifies valid
+ * candidate entries returning their ids.
+ */
+public class SearchEngine
+ extends AbstractLogEnabled
+{
+ private Optimizer m_optimizer = new DefaultOptimizer() ;
+
+
+ public Optimizer getOptimizer()
+ {
+ return m_optimizer ;
+ }
+
+
+ public ExprNode addScopeNode(ExprNode a_node, String a_baseDn, int a_scope)
+ {
+ ScopeNode l_scopeNode = new ScopeNode(
+ DerefAliasesEnum.NEVERDEREFALIASES, a_baseDn, a_scope) ;
+ BranchNode l_top = new BranchNode(BranchNode.AND) ;
+ l_top.getChildren().add(l_scopeNode) ;
+ l_top.getChildren().add(a_node) ;
+ return l_top ;
+ }
+
+
+ public Cursor search(Database a_db,
+ ExprNode a_filter,
+ String a_baseDn,
+ int a_scope)
+ throws BackendException, NamingException
+ {
+ Cursor l_cursor = null ;
+ ExprNode l_root = addScopeNode(a_filter, a_baseDn, a_scope) ;
+ m_optimizer.annotate(a_db, l_root) ;
+ l_cursor = buildSearchCursor(a_db, l_root) ;
+ l_cursor.enableLogging(getLogger()) ;
+ return l_cursor ;
+ }
+
+
+ ///////////////////////////////////////////////////////////////
+ // C U R S O R B U I L D I N G F U N C T I O N S //
+ ///////////////////////////////////////////////////////////////
+
+
+ public Cursor buildSearchCursor(final Database a_db, final ExprNode a_node)
+ throws BackendException, NamingException
+ {
+ Cursor l_cursor = null ;
+
+ if ( a_node instanceof ScopeNode )
+ {
+ return buildScopeCursor( a_db, ( ScopeNode ) a_node ) ;
+ }
+
+ if(a_node.isLeaf()) {
+ LeafNode l_leaf = (LeafNode) a_node ;
+
+ switch(l_leaf.getAssertionType()) {
+ case(LeafNode.APPROXIMATE):
+ l_cursor = a_db.getIndexCursor(l_leaf.getAttribute(),
+ ((SimpleNode)l_leaf).getValue()) ;
+ break ;
+ case(LeafNode.EQUALITY):
+ l_cursor = a_db.getIndexCursor(l_leaf.getAttribute(),
+ ((SimpleNode)l_leaf).getValue()) ;
+ break ;
+ case(LeafNode.EXTENSIBLE):
+ // N O T I M P L E M E N T E D Y E T !
+ throw new NotImplementedException() ;
+ //break ;
+ case(LeafNode.GREATEREQ):
+ l_cursor = a_db.getIndexCursor(l_leaf.getAttribute(),
+ ((SimpleNode)l_leaf).getValue(), true) ;
+ break ;
+ case(LeafNode.LESSEQ):
+ l_cursor = a_db.getIndexCursor(l_leaf.getAttribute(),
+ ((SimpleNode)l_leaf).getValue(), false) ;
+ break ;
+ case(LeafNode.PRESENCE):
+ l_cursor = a_db.getIndexCursor(Schema.EXISTANCE_ATTR,
+ l_leaf.getAttribute().toLowerCase()) ;
+ break ;
+ case(LeafNode.SUBSTRING):
+ l_cursor = buildSubstringCursor(a_db, (SubstringNode) l_leaf) ;
+ break ;
+ default:
+ throw new IllegalArgumentException("Unknown leaf assertion") ;
+ }
+ }
+ else if (a_node instanceof ScopeNode )
+ {
+ l_cursor = buildScopeCursor(a_db, (ScopeNode) a_node) ;
+ }
+ else
+ {
+ BranchNode l_branch = (BranchNode) a_node ;
+ switch(l_branch.getOperator()) {
+ case(BranchNode.AND):
+ l_cursor = buildConjunctionCursor(a_db, l_branch) ;
+ break ;
+ case(BranchNode.NOT):
+ l_cursor = buildNegationCursor(a_db, l_branch) ;
+ break ;
+ case(BranchNode.OR):
+ l_cursor = buildDisjunctionCursor(a_db, l_branch) ;
+ break ;
+ default:
+ throw new IllegalArgumentException("Unknown branch operator") ;
+ }
+ }
+
+ l_cursor.enableLogging(getLogger()) ;
+ return l_cursor ;
+ }
+
+
+ public Cursor buildScopeCursor(final Database a_db, final ScopeNode a_node)
+ throws BackendException, NamingException
+ {
+ switch(a_node.getScope()) {
+ case(Backend.BASE_SCOPE):
+ final BigInteger l_id = a_db.getEntryId(a_node.getBaseDn()) ;
+ final IndexRecord l_record =
+ new IndexRecord() ;
+ l_record.setEntryId(l_id) ;
+ l_record.setIndexKey(a_node.getBaseDn()) ;
+
+ return new Cursor() {
+ public Object advance()
+ throws NamingException
+ { super.close() ; return l_record ; }
+ public void freeResources() { }
+ public boolean canAdvance()
+ { return(!super.isClosed()) ; }
+ } ;
+ case(Backend.SINGLE_SCOPE):
+ return a_db.getChildren(a_db.getEntryId(a_node.getBaseDn())) ;
+ case(Backend.SUBTREE_SCOPE):
+ Assertion l_assertion = new Assertion()
+ {
+ public boolean assertCandidate(Object a_candidate)
+ throws BackendException
+ {
+ IndexRecord l_rec = (IndexRecord) a_candidate ;
+ String l_dn = a_db.getEntryDn(l_rec.getEntryId()) ;
+ return l_dn.endsWith(a_node.getBaseDn()) ;
+ }
+ } ;
+
+ // Gets a cursor over all elements
+ Cursor l_cursor = a_db.getIndexCursor(Schema.DN_ATTR) ;
+ return new PrefetchCursor(l_cursor, l_assertion) ;
+ default:
+ throw new BackendException("Unrecognized search scope!") ;
+ }
+ }
+
+
+ public Cursor buildSubstringCursor(final Database a_db,
+ final SubstringNode a_node)
+ throws BackendException, NamingException
+ {
+ Cursor l_cursor = null ;
+ RE l_regex = null ;
+
+ try {
+ l_regex = a_node.getRegex() ;
+ } catch(RESyntaxException e) {
+ throw new BackendException("SubstringNode '" + a_node + "' had "
+ + "encountered syntax exception: " + e.getMessage(), e) ;
+ }
+
+ if(a_node.getInitial() != null) {
+ l_cursor = a_db.getIndexCursor(a_node.getAttribute(), l_regex,
+ a_node.getInitial()) ;
+ } else {
+ l_cursor = a_db.getIndexCursor(a_node.getAttribute(), l_regex) ;
+ }
+
+ return l_cursor ;
+ }
+
+
+ /**
+ * Method involved in chain recursion while constructing the search cursor
+ * used to handle the Disjunction expression case.
+ */
+ public Cursor buildDisjunctionCursor(final Database a_db,
+ final BranchNode a_node)
+ throws BackendException, NamingException
+ {
+ Cursor l_cursor = null ;
+ ArrayList l_list = a_node.getChildren() ;
+ Cursor [] l_childCursors = new Cursor [l_list.size()] ;
+
+ // Recursively create Cursors for each of the child expression nodes.
+ for(int ii = 0 ; ii < l_childCursors.length; ii++) {
+ l_childCursors[ii] =
+ buildSearchCursor(a_db, (ExprNode) l_list.get(ii)) ;
+ }
+
+ // Create the Cursor enable logging on it and return.
+ l_cursor = new DisjunctionCursor(l_childCursors) ;
+ l_cursor.enableLogging(getLogger()) ;
+ return l_cursor ;
+ }
+
+
+ /**
+ * Method involved in chain recursion while constructing the search cursor
+ * used to handle the Negation expression case.
+ */
+ public Cursor buildNegationCursor(final Database a_db,
+ final BranchNode a_node)
+ throws BackendException, NamingException
+ {
+ Cursor l_childCursor = null ;
+ Cursor l_cursor = null ;
+ final ExprNode l_childNode =
+ (ExprNode) a_node.getChildren().get(0) ;
+
+ // Iterates over entire set of index values.
+ if(l_childNode.isLeaf()) {
+ LeafNode l_child = (LeafNode) l_childNode ;
+ l_childCursor = a_db.getIndexCursor(l_child.getAttribute()) ;
+ } else { // Iterates over the entire set of entries.
+ l_childCursor = a_db.getIndexCursor(Schema.DN_ATTR) ;
+ }
+
+ l_childCursor.enableLogging(getLogger()) ;
+
+ Assertion l_assertion = new Assertion()
+ {
+ public boolean assertCandidate(Object a_candidate)
+ throws BackendException, NamingException
+ {
+ IndexRecord l_rec = (IndexRecord) a_candidate ;
+ // NOTICE THE ! HERE
+ // The candidate is valid if it does not pass assertion. A
+ // candidate that passes assertion is therefore invalid.
+ return !assertExpression(a_db, l_childNode, l_rec.getEntryId()) ;
+ }
+ } ;
+ l_cursor = new PrefetchCursor(l_childCursor, l_assertion, true) ;
+ l_cursor.enableLogging(getLogger()) ;
+ return l_cursor ;
+ }
+
+
+ /**
+ * Method involved in chain recursion while constructing the search cursor
+ * used to handle the Conjunction expression case.
+ */
+ public Cursor buildConjunctionCursor(final Database a_db,
+ final BranchNode a_node)
+ throws BackendException, NamingException
+ {
+ int l_minIndex = 0 ;
+ int l_minValue = Integer.MAX_VALUE ;
+ int l_value = Integer.MAX_VALUE ;
+ ExprNode l_node = null ;
+ Cursor l_cursor = null ;
+
+ // We scan the child nodes of a branch node searching for the child
+ // expression node with the smallest scan count. This is the child
+ // we will use for iteration by creating a cursor over its expression.
+ final ArrayList l_list = a_node.getChildren() ;
+ for(int ii = 0 ; ii < l_list.size(); ii++) {
+ l_node = (ExprNode) l_list.get(ii) ;
+ l_value = ((BigInteger) l_node.get("count")).intValue() ;
+ l_minValue = Math.min(l_minValue, l_value) ;
+
+ if(l_minValue == l_value) {
+ l_minIndex = ii ;
+ }
+ }
+
+ // Once found we construct the child cursor and the conjunction cursor.
+ final ExprNode l_cursorNode = (ExprNode) l_list.get(l_minIndex) ;
+
+ Assertion l_assertion = new Assertion()
+ {
+ public boolean assertCandidate(Object a_candidate)
+ throws BackendException, NamingException
+ {
+ IndexRecord l_rec = (IndexRecord) a_candidate ;
+
+ for(int ii = 0 ; ii < l_list.size(); ii++) {
+ ExprNode l_child = (ExprNode) l_list.get(ii) ;
+
+ if(l_child == l_cursorNode) {
+ continue ;
+ } else if(!assertExpression(a_db, l_child,
+ l_rec.getEntryId())) {
+ return false ;
+ }
+ }
+
+ return true ;
+ }
+ } ;
+
+ Cursor l_childCursor = buildSearchCursor(a_db, l_cursorNode) ;
+ l_cursor = new PrefetchCursor(l_childCursor, l_assertion) ;
+ l_cursor.enableLogging(getLogger()) ;
+ return l_cursor ;
+ }
+
+
+ /////////////////////////////////////////////////////////////////////
+ // E X P R E S S I O N A S S E R T I O N F U N C T I O N S //
+ /////////////////////////////////////////////////////////////////////
+
+
+ public boolean assertExpression(final Database a_db, final ExprNode a_node,
+ final BigInteger a_id)
+ throws BackendException, NamingException
+ {
+ if (a_node instanceof ScopeNode)
+ {
+ return assertScope( a_db, (ScopeNode) a_node, a_id ) ;
+ }
+ if(a_node.isLeaf()) {
+ return assertLeaf(a_db, (LeafNode) a_node, a_id) ;
+ }
+
+ return assertBranch(a_db, (BranchNode) a_node, a_id) ;
+ }
+
+
+ public boolean assertBranch(final Database a_db, final BranchNode a_node,
+ final BigInteger a_id)
+ throws BackendException, NamingException
+ {
+ switch(a_node.getOperator()) {
+ case(BranchNode.OR):
+ Iterator l_children = a_node.getChildren().iterator() ;
+ while(l_children.hasNext()) {
+ ExprNode l_child = (ExprNode) l_children.next() ;
+ if(assertExpression(a_db, l_child, a_id)) {
+ return true ;
+ }
+ }
+
+ return false ;
+ case(BranchNode.AND):
+ l_children = a_node.getChildren().iterator() ;
+ while(l_children.hasNext()) {
+ ExprNode l_child = (ExprNode) l_children.next() ;
+ if(!assertExpression(a_db, l_child, a_id)) {
+ return false ;
+ }
+ }
+
+ return true ;
+ case(BranchNode.NOT):
+ ArrayList l_childArray = a_node.getChildren() ;
+ if(l_childArray.size() > 0) {
+ return !assertExpression(a_db,
+ (ExprNode) l_childArray.get(0), a_id) ;
+ }
+
+ throw new BackendException("Negation has no child: " + a_node) ;
+ default:
+ throw new BackendException("Unrecognized branch node operator: "
+ + a_node.getOperator()) ;
+ }
+ }
+
+
+ public boolean assertLeaf(final Database a_db, final LeafNode a_node,
+ final BigInteger a_id)
+ throws BackendException, NamingException
+ {
+ switch(a_node.getAssertionType()) {
+ case(LeafNode.APPROXIMATE):
+ return a_db.assertIndexValue(((SimpleNode) a_node).getAttribute(),
+ ((SimpleNode) a_node).getValue(), a_id) ;
+ case(LeafNode.EQUALITY):
+ return a_db.assertIndexValue(((SimpleNode) a_node).getAttribute(),
+ ((SimpleNode) a_node).getValue(), a_id) ;
+ case(LeafNode.EXTENSIBLE):
+ throw new NotImplementedException() ;
+ case(LeafNode.GREATEREQ):
+ return a_db.assertIndexValue(((SimpleNode) a_node).getAttribute(),
+ ((SimpleNode) a_node).getValue(), a_id, true) ;
+ case(LeafNode.LESSEQ):
+ return a_db.assertIndexValue(((SimpleNode) a_node).getAttribute(),
+ ((SimpleNode) a_node).getValue(), a_id, false) ;
+ case(LeafNode.PRESENCE):
+ return a_db.assertIndexValue(Schema.EXISTANCE_ATTR,
+ ((PresenceNode) a_node).getAttribute().toLowerCase(), a_id) ;
+ case(LeafNode.SUBSTRING):
+ return assertSubstring(a_db, (SubstringNode) a_node, a_id) ;
+ default:
+ throw new BackendException("Unrecognized leaf node type: "
+ + a_node.getAssertionType()) ;
+ }
+ }
+
+
+ public boolean assertScope(final Database a_db, final ScopeNode a_node,
+ final BigInteger a_id)
+ throws BackendException, NamingException
+ {
+ String l_dn = a_db.getEntryDn(a_id) ;
+
+ switch(a_node.getScope()) {
+ case(Backend.BASE_SCOPE):
+ return l_dn.equals(a_node.getBaseDn()) ;
+ case(Backend.SINGLE_SCOPE):
+ Object l_key = a_db.getEntryId(a_node.getBaseDn()) ;
+ return a_db.assertIndexValue(Schema.HIERARCHY_ATTR, l_key, a_id) ;
+ case(Backend.SUBTREE_SCOPE):
+ return l_dn.endsWith(a_node.getBaseDn()) ;
+ default:
+ throw new BackendException("Unrecognized search scope!") ;
+ }
+ }
+
+
+ public boolean assertSubstring(final Database a_db,
+ final SubstringNode a_node,
+ final BigInteger a_id)
+ throws BackendException, NamingException
+ {
+ RE l_regex = null ;
+ Index l_index = a_db.getIndex(a_node.getAttribute()) ;
+ Cursor l_cursor = l_index.getReverseCursor(a_id) ;
+
+ try {
+ l_regex = a_node.getRegex() ;
+ } catch(RESyntaxException e) {
+ throw new BackendException("SubstringNode '" + a_node + "' had "
+ + "encountered syntax exception: " + e.getMessage(), e) ;
+ }
+
+ while(l_cursor.hasMore()) {
+ IndexRecord l_rec = (IndexRecord) l_cursor.next() ;
+ if(l_regex.match((String) l_rec.getIndexKey())) {
+ l_cursor.close() ;
+ return true ;
+ }
+ }
+
+ return false ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/table/DupsCursor.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/table/DupsCursor.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,111 @@
+/*
+ * $Id: DupsCursor.java,v 1.3 2003/03/13 18:27:30 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm.table ;
+
+
+import java.util.TreeSet ;
+import java.util.Iterator ;
+import java.util.ArrayList ;
+import java.util.Collections ;
+
+import javax.naming.NamingException ;
+
+import org.apache.eve.backend.Cursor ;
+import org.apache.eve.backend.BackendException ;
+
+import jdbm.helper.Tuple ;
+
+
+/**
+ * Cursor that iterates over duplicate values nested into a value using a
+ * TreeSet.
+ *
+ * @warning The Tuple returned by this Cursor is always the same instance object
+ * returned every time. It is reused to for the sake of efficency rather than
+ * creating a new tuple for each advance() call.
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.3 $
+ */
+public class DupsCursor
+ extends Cursor
+{
+ private final Tuple m_returned = new Tuple() ;
+ private final Tuple m_prefetched = new Tuple() ;
+ private final NoDupsCursor m_cursor ;
+
+ private Iterator m_iterator ;
+ private Tuple m_duplicates ;
+
+
+ DupsCursor(NoDupsCursor a_cursor)
+ throws BackendException
+ {
+ m_cursor = a_cursor ;
+
+ try {
+ // Protect against closed cursors
+ if(m_cursor.isClosed()) {
+ close() ;
+ return ;
+ }
+
+ prefetch() ;
+ } catch(NamingException e) { /* NEVER THROWN */ }
+ }
+
+
+ private void prefetch()
+ throws BackendException, NamingException
+ {
+ while(null == m_iterator || !m_iterator.hasNext()) {
+ if(m_cursor.hasMoreElements()) {
+ m_duplicates = (Tuple) m_cursor.next() ;
+ TreeSet l_set = (TreeSet) m_duplicates.getValue() ;
+
+ if(m_cursor.doAscendingScan()) {
+ m_iterator = l_set.iterator() ;
+ } else {
+ ArrayList l_list = new ArrayList(l_set.size()) ;
+ l_list.addAll(l_set) ;
+ Collections.reverse(l_list) ;
+ m_iterator = l_list.iterator() ;
+ }
+ } else {
+ close() ;
+ return ;
+ }
+ }
+
+ m_prefetched.setKey(m_duplicates.getKey()) ;
+ m_prefetched.setValue(m_iterator.next()) ;
+ }
+
+
+ public Object advance()
+ throws BackendException, NamingException
+ {
+ m_returned.setKey(m_prefetched.getKey()) ;
+ m_returned.setValue(m_prefetched.getValue()) ;
+
+ prefetch() ;
+
+ return m_returned ;
+ }
+
+
+ public boolean canAdvance()
+ {
+ return !isClosed() ;
+ }
+
+
+ public void freeResources() { /* Does nothing! */ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/table/JdbmTable.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/table/JdbmTable.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,989 @@
+/*
+ * $Id: JdbmTable.java,v 1.13 2003/03/13 18:27:31 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm.table ;
+
+
+import java.util.TreeSet ;
+import java.util.SortedSet ;
+import java.util.ArrayList ;
+import java.util.Collections ;
+import java.io.IOException ;
+
+import org.apache.eve.backend.Cursor ;
+import org.apache.eve.backend.EmptyCursor ;
+import org.apache.eve.backend.SingletonCursor ;
+import org.apache.eve.backend.BackendException ;
+
+import jdbm.helper.MRU ;
+import jdbm.btree.BTree ;
+import jdbm.helper.Tuple ;
+import jdbm.helper.Comparator ;
+import jdbm.helper.ObjectCache ;
+import jdbm.helper.TupleBrowser ;
+import jdbm.recman.RecordManager ;
+
+import org.apache.avalon.framework.ExceptionUtil ;
+import org.apache.avalon.framework.logger.AbstractLogEnabled ;
+
+
+/**
+ * A jdbm Btree wrapper that enables duplicate sorted keys using collections.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.13 $
+ */
+public class JdbmTable
+ extends AbstractLogEnabled implements Table
+{
+ private static final int CACHE_SIZE = 1000 ;
+ private static final String SZSUFFIX = "_btree_sz" ;
+
+ private final String m_name ;
+ private final RecordManager m_recMan ;
+ private final boolean allowsDuplicates ;
+ private final TupleComparator m_comparator ;
+
+ private int m_count = 0 ;
+ private BTree m_bt ;
+ private TupleRenderer m_renderer ;
+
+
+ //////////////////
+ // Constructors //
+ //////////////////
+
+ /**
+ * A jdbm Btree backed table.
+ */
+ public JdbmTable(String a_name, boolean allowsDuplicates,
+ RecordManager a_manager, TupleComparator a_comparator)
+ throws BackendException
+ {
+ m_name = a_name ;
+ m_recMan = a_manager ;
+ m_comparator = a_comparator ;
+ this.allowsDuplicates = allowsDuplicates ;
+
+ try {
+ ObjectCache m_cache =
+ new ObjectCache(m_recMan, new MRU(CACHE_SIZE)) ;
+
+ long l_recId = m_recMan.getNamedObject(m_name) ;
+ if(l_recId != 0) {
+ m_bt = BTree.load(m_recMan, m_cache, l_recId) ;
+ l_recId = m_recMan.getNamedObject(m_name + SZSUFFIX) ;
+ m_count = ((Integer) m_recMan.fetchObject(l_recId)).intValue() ;
+ } else {
+ m_bt = new BTree(m_recMan, m_cache,
+ (jdbm.helper.Comparator) a_comparator.getKeyComparator()) ;
+ l_recId = m_bt.getRecid() ;
+ m_recMan.setNamedObject(m_name, l_recId) ;
+
+ l_recId = m_recMan.insert(new Integer(0)) ;
+ m_recMan.setNamedObject(m_name + SZSUFFIX, l_recId) ;
+ }
+ } catch(Throwable e) {
+ throw new BackendException("Failed to load/create Btree:\n"
+ + ExceptionUtil.printStackTrace(e), e) ;
+ }
+ }
+
+
+ /**
+ * A jdbm Btree backed table.
+ */
+ public JdbmTable(String a_name, RecordManager a_manager,
+ TableComparator a_keyComparator)
+ throws BackendException
+ {
+ this(a_name, false, a_manager, new KeyOnlyComparator(a_keyComparator)) ;
+ }
+
+
+ /**
+ * Gets the comparator used by this Table: may be null if this Table was
+ * not initialized with one.
+ *
+ * @return the final comparator instance or null if this Table was not
+ * created with one.
+ */
+ public TupleComparator getComparator()
+ {
+ return m_comparator ;
+ }
+
+
+ /**
+ * Checks to see if this Table has enabled the use of duplicate keys.
+ *
+ * @return true if duplicate keys are enabled, false otherwise.
+ */
+ public boolean isDupsEnabled()
+ {
+ return allowsDuplicates;
+ }
+
+
+ /**
+ * Gets the name of this Table.
+ *
+ * @return the name
+ */
+ public String getName()
+ {
+ return m_name ;
+ }
+
+
+ /**
+ * Gets the data renderer used by this Table to display or log records keys
+ * and values.
+ *
+ * @return the renderer used
+ */
+ public TupleRenderer getRenderer()
+ {
+ return m_renderer ;
+ }
+
+
+ /**
+ * Sets the data renderer to by used by this Table to display or log record
+ * keys and values.
+ *
+ * @param a_renderer the DataRenderer instance to used as the renderer.
+ */
+ public void setRenderer(TupleRenderer a_renderer)
+ {
+ m_renderer = a_renderer ;
+ }
+
+
+ /**
+ * Checks to see if this Table has enabled sorting on the values of
+ * duplicate keys. This will always return true but may change after
+ * this release.
+ *
+ * @return true if duplicate key values are sorted, false otherwise.
+ */
+ public boolean isSortedDupsEnabled()
+ {
+ // If duplicates are enabled than duplicates will be maintained in
+ // sorted order.
+ return allowsDuplicates ;
+ }
+
+
+ /**
+ * This operation is not supported by this implementation. Will always
+ * throw a UnsupportedOperationException.
+ *
+ * @param a_key the Object key to count.
+ * @param isGreaterThan boolean set to true to count for greater than and
+ * equal to record keys, or false for less than or equal to keys.
+ * @return the number of keys greater or less than a_key.
+ * @throws BackendException if there is a failure to read the underlying Db
+ */
+ public int count(Object a_key, boolean isGreaterThan)
+ throws BackendException
+ {
+ throw new UnsupportedOperationException() ;
+ }
+
+
+ /**
+ * Gets the count of the number of records in this Table with a specific
+ * key: returns the number of duplicates for a key.
+ *
+ * @param a_key the Object key to count.
+ * @return the number of duplicate records for a key.
+ * @throws BackendException if there is a failure to read the underlying Db
+ */
+ public int count(Object a_key)
+ throws BackendException
+ {
+ if(!allowsDuplicates) {
+ getLogger().warn("JdbmTable.count(Object):"
+ + " Should not be calling this method for tables that"
+ + " do not support duplicates.") ;
+
+ if(null == getRaw(a_key)) {
+ return 0 ;
+ } else {
+ return 1 ;
+ }
+ }
+
+ TreeSet l_set = (TreeSet) getRaw(a_key) ;
+
+ if(l_set != null) {
+ return l_set.size() ;
+ }
+
+ return 0 ;
+ }
+
+
+ /**
+ *
+ * @return the number of keys
+ * @throws BackendException if there is a failure to read the underlying Db
+ */
+ public int count()
+ throws BackendException
+ {
+ return m_count ;
+ }
+
+
+ /**
+ * Gets the value of a record by key if the key exists. If this Table
+ * allows duplicate keys then the first key will be returned. If this
+ * Table is also a Btree that first key will be the smallest key in the
+ * Table as specificed by this Table's comparator or the default berkeley
+ * bytewise lexical comparator.
+ *
+ * @param a_key the key of the record
+ * @return the value of the record with a_key if a_key exists or null if
+ * no such record exists.
+ * @throws BackendException if there is a failure to read the underlying Db
+ */
+ public Object get(Object a_key)
+ throws BackendException
+ {
+ if(allowsDuplicates) {
+ TreeSet l_set = (TreeSet) getRaw(a_key) ;
+ if(null == l_set || l_set.size() == 0) {
+ return null ;
+ } else {
+ return l_set.first() ;
+ }
+ }
+
+ return getRaw(a_key) ;
+ }
+
+
+ /**
+ * Checks to see if this table has a record with a key equal to the
+ * argument key with a value greater/less than or equal to the value
+ * argument provided. The key argument <strong>MUST</strong> exist for
+ * this call to return true and the underlying Db must be a Btree that
+ * allows for sorted duplicate values. The entire basis to this method
+ * depends on the fact that duplicate key values are sorted according to
+ * a valid value comparator function.
+ *
+ * @param a_key the key Object
+ * @param a_val the value Object to compare values to
+ * @param isGreaterThan boolean for greater than or less then comparison
+ * @return true if a record with a key greater/less than the key argument
+ * exists, false otherwise
+ * @throws BackendException if there is a failure to read the underlying Db
+ * or if the underlying Db does not allow sorted duplicate values.
+ */
+ public boolean has(Object a_key, Object a_val, boolean isGreaterThan)
+ throws BackendException
+ {
+ if(!allowsDuplicates) {
+ getLogger().warn("JdbmTable.has(Object, Object, boolean):"
+ + " Should not be calling this method for tables that"
+ + " do not support duplicates.") ;
+
+ Object l_val = getRaw(a_key) ;
+
+ // key does not exist so return nothing
+ if(null == l_val) {
+ return false ;
+ }
+ // l_val == a_val return tuple
+ else if(a_val.equals(l_val)) {
+ return true ;
+ }
+ // l_val >= a_val and test is for greater then return tuple
+ else if(m_comparator.compareValue(l_val, a_val) >= 1 &&
+ isGreaterThan)
+ {
+ return true ;
+ }
+ // l_val <= a_val and test is for lesser then return tuple
+ else if(m_comparator.compareValue(l_val, a_val) <= 1 &&
+ !isGreaterThan)
+ {
+ return true ;
+ }
+ // key's value does not equal a_val and conditions not satisfied.
+ else {
+ return false ;
+ }
+ }
+
+ TreeSet l_set = (TreeSet) getRaw(a_key) ;
+ if(null == l_set || l_set.size() == 0) {
+ return false ;
+ }
+
+ SortedSet l_subset = null ;
+ if(isGreaterThan) {
+ l_subset = l_set.tailSet(a_val) ;
+ } else {
+ l_subset = l_set.headSet(a_val) ;
+ }
+
+ if(l_subset.size() > 0 || l_set.contains(a_val)) {
+ return true ;
+ }
+
+ return false ;
+ }
+
+
+ /**
+ * Checks to see if this table has a record with a key greater/less than or
+ * equal to the key argument. The key argument need not exist for this
+ * call to return true.
+ *
+ * @param a_key the key Object to compare keys to
+ * @param isGreaterThan boolean for greater than or less then comparison
+ * @return true if a record with a key greater/less than the key argument
+ * exists, false otherwise
+ * @throws BackendException if there is a failure to read the underlying Db
+ */
+ public boolean has(Object a_key, boolean isGreaterThan)
+ throws BackendException
+ {
+ try {
+ // See if we can find the border between keys greater than and less
+ // than in the set of keys. This will be the spot we search from.
+ Tuple l_tuple = m_bt.findGreaterOrEqual(a_key) ;
+
+ // Test for equality first since it satisfies both greater/less than
+ if(null != l_tuple &&
+ m_comparator.compareKey(l_tuple.getKey(), a_key) == 0)
+ {
+ return true ;
+ }
+
+ // Greater searches are easy and quick thanks to findGreaterOrEqual
+ if(isGreaterThan) {
+ // A null return above means there were no equal or greater keys
+ if(null == l_tuple) {
+ return false ;
+ }
+
+ // Not Null! - we found a tuple with equal or greater key value
+ return true ;
+ }
+
+ // Less than searches occur below and are not as efficient or easy.
+ // We need to scan up from the begining if findGreaterOrEqual failed
+ // or scan down if findGreaterOrEqual succeed.
+ TupleBrowser l_browser = null ;
+ if(null == l_tuple) {
+ // findGreaterOrEqual failed so we create a tuple and scan from
+ // the lowest values up via getNext comparing each key to a_key
+ l_tuple = new Tuple() ;
+ l_browser = m_bt.browse() ;
+
+ // We should at most have to read one key. If 1st key is not
+ // less than or equal to a_key then all keys are > a_key
+ // since the keys are assorted in ascending order based on the
+ // comparator.
+ while(l_browser.getNext(l_tuple)) {
+ if(m_comparator.compareKey(l_tuple.getKey(), a_key) <= 0) {
+ return true ;
+ } else { // Short the search to prevent wasted cycling
+ return false ;
+ }
+ }
+ } else {
+ // findGreaterOrEqual succeeded so use the existing tuple and
+ // scan the down from the highest key less than a_key via
+ // getPrevious while comparing each key to a_key.
+ l_browser = m_bt.browse(l_tuple.getKey()) ;
+
+ // The above call positions the browser just before the given
+ // key so we need to step forward once then back. Remember this
+ // key represents a key greater than or equal to a_key.
+ if(m_comparator.compareKey(l_tuple.getKey(), a_key) <= 0) {
+ return true ;
+ }
+ l_browser.getNext(l_tuple) ;
+
+ // We should at most have to read one key, but we don't short
+ // the search as in the search above first because the chance of
+ // unneccessarily looping is nil since values get smaller.
+ while(l_browser.getPrevious(l_tuple)) {
+ if(m_comparator.compareKey(l_tuple.getKey(), a_key) <= 0) {
+ return true ;
+ }
+ }
+ }
+ } catch(IOException e) {
+ String l_msg = "Failed to lookup whether a key " ;
+ if(isGreaterThan) {
+ l_msg += "greater " ;
+ } else {
+ l_msg += "less " ;
+ }
+ l_msg += "than or equal to a key " + renderKey(a_key)
+ + " exists:\n" + ExceptionUtil.printStackTrace(e) ;
+ throw new BackendException(l_msg, e) ;
+ }
+
+ return false ;
+ }
+
+
+ /**
+ * Checks to see if this table has a key with a specific value.
+ *
+ * @param a_key the key Object to check for
+ * @param a_value the value Object to check for
+ * @return true if a record with the key and value exists, false otherwise.
+ * @throws BackendException if there is a failure to read the underlying Db
+ */
+ public boolean has(Object a_key, Object a_value)
+ throws BackendException
+ {
+ if(allowsDuplicates) {
+ TreeSet l_set = (TreeSet) getRaw(a_key) ;
+ if(null == l_set) {
+ return false ;
+ }
+
+ return l_set.contains(a_value) ;
+ }
+
+ Object l_obj = getRaw(a_key) ;
+ if(null == l_obj) {
+ return false ;
+ }
+
+ return l_obj.equals(a_value) ;
+ }
+
+
+ /**
+ * Checks to see if this table has a key: same as a get call with a check to
+ * see if the returned value is null or not.
+ *
+ * @param a_key the Object of the key to check for
+ * @return true if the key exists, false otherwise.
+ * @throws BackendException if there is a failure to read the underlying Db
+ */
+ public boolean has(Object a_key)
+ throws BackendException
+ {
+ return getRaw(a_key) != null ;
+ }
+
+
+ /**
+ * Puts a record into this Table.
+ *
+ * @param a_key the key of the record
+ * @param a_value the value of the record.
+ * @return the last value present for a_key or null if this the key did not
+ * exist before. For tables allowing duplicates the return value is null.
+ * @throws BackendException if there is a failure to read or write to
+ * the underlying Db
+ */
+ public Object put(Object a_key, Object a_value)
+ throws BackendException
+ {
+ Object l_replaced = null ;
+
+ if(allowsDuplicates) {
+ TreeSet l_set = (TreeSet) getRaw(a_key) ;
+ if(null == l_set) {
+ l_set = new TreeSet(m_comparator.getValueComparator()) ;
+ } else if(l_set.contains(a_value)) {
+ return a_value ;
+ }
+
+ l_set.add(a_value) ;
+ putRaw(a_key, l_set, true) ;
+ m_count++ ;
+ return null ;
+ }
+
+ l_replaced = putRaw(a_key, a_value, true) ;
+
+ if(null == l_replaced) {
+ m_count++ ;
+ }
+
+ return l_replaced ;
+ }
+
+
+ /**
+ * Removes a single specific record with a_key and a_value from this Table.
+ *
+ * @param the key of the record to remove.
+ * @param the value of the record to remove.
+ * @return a_value if (a_key, a_value) exists to be removed else null
+ * @throws BackendException if there is a failure to read or write to
+ * the underlying Db
+ */
+ public Object remove(Object a_key, Object a_value)
+ throws BackendException
+ {
+ if(allowsDuplicates) {
+ TreeSet l_set = (TreeSet) getRaw(a_key) ;
+
+ if(null == l_set) {
+ return null ;
+ }
+
+ // If removal succeeds then remove if set is empty else replace it
+ if(l_set.remove(a_value)) {
+ if(l_set.isEmpty()) {
+ removeRaw(a_key) ;
+ } else {
+ putRaw(a_key, l_set, true) ;
+ }
+
+ // Decrement counter if removal occurs.
+ m_count-- ;
+ return a_value ;
+ }
+
+ return null ;
+ }
+
+ Object l_removed = null ;
+
+ // Remove the value only if it is the same as a_value.
+ if(getRaw(a_key).equals(a_value)) {
+ return removeRaw(a_key) ;
+ }
+
+ return null ;
+ }
+
+
+ /**
+ * Removes all records with a_key from this Table.
+ *
+ * @param the key of the records to remove.
+ * @return if a_key exists its value is returned. The value will be a
+ * TreeSet containing sorted duplicate values if this table allows
+ * duplicates.
+ * @throws BackendException if there is a failure to read or write to
+ * the underlying Db
+ */
+ public Object remove(Object a_key)
+ throws BackendException
+ {
+ Object l_returned = removeRaw(a_key) ;
+
+ if(null == l_returned) {
+ return null ;
+ }
+
+ if(allowsDuplicates) {
+ TreeSet l_set = (TreeSet) l_returned ;
+ this.m_count -= l_set.size() ;
+ return l_set.first() ;
+ }
+
+ this.m_count-- ;
+ return l_returned ;
+ }
+
+
+ //////////////////////
+ // Cursor Overloads //
+ //////////////////////
+
+
+ /**
+ * Sets a cursor to the first record in the Table and enables single
+ * next steps across all records.
+ *
+ * @throws BackendException if the underlying cursor could not be set.
+ */
+ public Cursor getCursor()
+ throws BackendException
+ {
+ Cursor l_cursor = null ;
+
+ try {
+ l_cursor = new NoDupsCursor(m_bt.browse(), true) ;
+ l_cursor.enableLogging(getLogger()) ;
+ } catch(IOException e) {
+ throw new BackendException("Could not create cursor over table "
+ + m_name + ":\n" + ExceptionUtil.printStackTrace(e), e) ;
+ }
+
+ if(allowsDuplicates) {
+ l_cursor = new DupsCursor((NoDupsCursor) l_cursor) ;
+ l_cursor.enableLogging(getLogger()) ;
+ return l_cursor ;
+ }
+
+ return l_cursor ;
+ }
+
+
+ /**
+ * Sets a cursor to the first record in the Table with a key value of
+ * a_key and enables single next steps across all duplicate records with
+ * this key. This cursor will only iterate over duplicates of the key.
+ *
+ * @param a_key the key to iterate over
+ * @throws BackendException if the underlying cursor could not be set
+ */
+ public Cursor getCursor(Object a_key)
+ throws BackendException
+ {
+ if(!allowsDuplicates) {
+ getLogger().warn("JdbmTable.getCursor(Object):"
+ + " Should not be calling this method for tables that"
+ + " do not support duplicates.") ;
+
+ Object l_val = getRaw(a_key) ;
+ if(null == l_val) {
+ return new EmptyCursor() ;
+ } else {
+ return new SingletonCursor(new Tuple(a_key, getRaw(a_key))) ;
+ }
+ }
+
+ TreeSet l_set = (TreeSet) getRaw(a_key) ;
+ if(l_set == null) {
+ return new EmptyCursor() ;
+ }
+
+ Cursor l_cursor = new TupleIteratorCursor(a_key, l_set.iterator()) ;
+ l_cursor.enableLogging(getLogger()) ;
+ return l_cursor ;
+ }
+
+
+ /**
+ * Sets a cursor to the first record in the Table with a key value
+ * greater/less than or equal to a_key and enables single next steps across
+ * all records with key values equal to or less/greater than a_key.
+ *
+ * @warning This cursor operation has no meaning for database table
+ * types other than the btree type since it relies on sorted keys.
+ * @param a_key the key to use to position this cursor to record with a key
+ * greater/less than or equal to it.
+ * @param isGreaterThan if true the cursor iterates up over ascending keys
+ * greater than or equal to the a_key argument, but if false this cursor
+ * iterates down over descending keys less than or equal to a_key argument.
+ * @throws BackendException if the underlying cursor could not be set
+ */
+ public Cursor getCursor(Object a_key, boolean isGreaterThan)
+ throws BackendException
+ {
+ Cursor l_cursor = null ;
+
+ try {
+ if(isGreaterThan) {
+ l_cursor = new NoDupsCursor(m_bt.browse(a_key), isGreaterThan) ;
+ } else {
+ /* According to the jdbm docs a browser is positioned right
+ * before a key greater than or equal to a_key. getNext() will
+ * return the next tuple with a key greater than or equal to
+ * a_key. getPrevious() used in descending scans for less than
+ * for equal to comparisions will not. We need to advance
+ * forward once and check if the returned Tuple key equals
+ * a_key. If it does then we do nothing feeding in the browser
+ * to the NoDupsCursor. If it does not we call getPrevious and
+ * pass it into the NoDupsCursor constructor.
+ */
+ Tuple l_tuple = new Tuple() ;
+ TupleBrowser l_browser = m_bt.browse(a_key) ;
+ if(l_browser.getNext(l_tuple)) {
+ Object l_greaterKey = l_tuple.getKey() ;
+ if(0 != m_comparator.compareKey(a_key, l_greaterKey)) {
+ // Make sure we don't return l_greaterKey in cursor
+ l_browser.getPrevious(l_tuple) ;
+ }
+ }
+
+ // If l_greaterKey != a_key above then it will not be returned.
+ l_cursor = new NoDupsCursor(l_browser, isGreaterThan) ;
+ }
+ } catch(IOException e) {
+ throw new BackendException("Failed to get TupleBrowser on table "
+ + m_name + " using key " + renderKey(a_key) + ":\n"
+ + ExceptionUtil.printStackTrace(e), e) ;
+ }
+
+ l_cursor.enableLogging(getLogger()) ;
+ if(allowsDuplicates) {
+ l_cursor = new DupsCursor((NoDupsCursor) l_cursor) ;
+ l_cursor.enableLogging(getLogger()) ;
+ }
+
+ return l_cursor ;
+ }
+
+
+ /**
+ * Sets a cursor to the first record in the Table with a key equal to
+ * the a_key argument whose value is greater/less than or equal to a_val and
+ * enables single next steps across all records with key equal to a_key.
+ * Hence this cursor will only iterate over duplicate keys where values are
+ * less/greater than or equal to a_val.
+ *
+ * @warning the underlying Db must have sorted duplicates enabled as in an
+ * Index.
+ * @param a_key the key to use to position this cursor to record with a key
+ * equal to it.
+ * @param a_val the value to use to position this cursor to record with a
+ * value greater/less than or equal to it.
+ * @param isGreaterThan if true the cursor iterates up over ascending values
+ * greater than or equal to the a_val argument, but if false this cursor
+ * iterates down over values less than or equal to a_val argument
+ * descending from the highest values going down.
+ * @throws BackendException if the underlying cursor could not be set or
+ * this method is called over a cursor on a table that does not have sorted
+ * duplicates enabled.
+ */
+ public Cursor getCursor(Object a_key, Object a_val, boolean isGreaterThan)
+ throws BackendException
+ {
+ if(!allowsDuplicates) {
+ getLogger().warn("JdbmTable.getCursor(Object, Object, boolean):"
+ + " Should not be calling this method for tables that"
+ + " do not support duplicates.") ;
+
+ Object l_val = getRaw(a_key) ;
+
+ // key does not exist so return nothing
+ if(null == l_val) {
+ return new EmptyCursor() ;
+ }
+ // l_val == a_val return tuple
+ else if(a_val.equals(l_val)) {
+ return new SingletonCursor(new Tuple(a_key, a_val)) ;
+ }
+ // l_val >= a_val and test is for greater then return tuple
+ else if(m_comparator.compareValue(l_val, a_val) >= 1 &&
+ isGreaterThan)
+ {
+ return new SingletonCursor(new Tuple(a_key, a_val)) ;
+ }
+ // l_val <= a_val and test is for lesser then return tuple
+ else if(m_comparator.compareValue(l_val, a_val) <= 1 &&
+ !isGreaterThan)
+ {
+ return new SingletonCursor(new Tuple(a_key, a_val)) ;
+ }
+ // key's value does not equal a_val and conditions not satisfied.
+ else {
+ return new EmptyCursor() ;
+ }
+ }
+
+ TreeSet l_set = (TreeSet) getRaw(a_key) ;
+ if(l_set == null) {
+ return new EmptyCursor() ;
+ }
+
+ if(isGreaterThan) {
+ return new TupleIteratorCursor(a_key,
+ l_set.tailSet(a_val).iterator()) ;
+ } else {
+ // Get all values from the smallest upto a_val and put them into
+ // a list. They will be in ascending order so we need to reverse
+ // the list after adding a_val which is not included in headSet.
+ SortedSet l_headset = l_set.headSet(a_val) ;
+ ArrayList l_list = new ArrayList(l_set.size() + 1) ;
+ l_list.addAll(l_headset) ;
+
+ // Add largest value (a_val) if it is in the set. TreeSet.headSet
+ // does not get a_val if a_val is in the set. So we add it now to
+ // the end of the list. List is now ascending from smallest to
+ // a_val
+ if(l_set.contains(a_val)) {
+ l_list.add(a_val) ;
+ }
+
+ // Reverse the list now we have descending values from a_val to the
+ // smallest value that a_key has. Return tuple cursor over list.
+ Collections.reverse(l_list) ;
+ return new TupleIteratorCursor(a_key, l_list.iterator()) ;
+ }
+ }
+
+
+ ////////////////////////////
+ // Maintenance Operations //
+ ////////////////////////////
+
+
+ /**
+ * Saves the count of this records to the database file but does not really
+ * close the file since other tables may still be open. This is because for
+ * Jdbm the RecordManager closes the file. Many btrees can be stored in a
+ * file. So this operation mearly performs clean up for this btree.
+ *
+ * @throws BackendException if there is a failure to save the store the
+ * count data.
+ */
+ public synchronized void close()
+ {
+ try {
+ sync() ;
+ } catch(BackendException e) {
+ getLogger().error("Faild to update and close database:\n", e) ;
+ }
+ }
+
+
+ /**
+ * Does nothing really. This is because for Jdbm the RecordManager needs
+ * to perform synchronization for the whole file. This table may be one
+ * btree in that file. So sychronization is handled higher up.
+ */
+ public void sync() throws BackendException
+ {
+ try {
+ long l_recId = m_recMan.getNamedObject(m_name + SZSUFFIX) ;
+ if(0 == l_recId) {
+ l_recId = m_recMan.insert(new Integer(m_count)) ;
+ } else {
+ m_recMan.update(l_recId, new Integer(m_count)) ;
+ }
+ } catch(IOException e) {
+ throw new BackendException("Failed to update and close database:\n"
+ + ExceptionUtil.printStackTrace(e), e) ;
+ }
+ }
+
+
+ /////////////////////////////
+ // Private Utility Methods //
+ /////////////////////////////
+
+
+ private String render(Object a_key, Object a_value)
+ {
+ StringBuffer l_buf = new StringBuffer() ;
+
+ l_buf.append("('") ;
+ if(null == m_renderer) {
+ l_buf.append(a_key.toString()) ;
+ } else {
+ l_buf.append(m_renderer.getKeyString(a_key)) ;
+ }
+ l_buf.append("', '") ;
+ if(null == m_renderer) {
+ l_buf.append(a_value.toString()) ;
+ } else {
+ l_buf.append(m_renderer.getValueString(a_value)) ;
+ }
+ l_buf.append("')") ;
+
+ return l_buf.toString() ;
+ }
+
+
+ private String renderKey(Object a_obj)
+ {
+ StringBuffer l_buf = new StringBuffer() ;
+
+ l_buf.append('\'') ;
+ if(null == m_renderer) {
+ l_buf.append(a_obj.toString()) ;
+ } else {
+ l_buf.append(m_renderer.getKeyString(a_obj)) ;
+ }
+ l_buf.append('\'') ;
+
+ return l_buf.toString() ;
+ }
+
+
+ private String renderValue(Object a_obj)
+ {
+ StringBuffer l_buf = new StringBuffer() ;
+
+ l_buf.append('\'') ;
+ if(null == m_renderer) {
+ l_buf.append(a_obj.toString()) ;
+ } else {
+ l_buf.append(m_renderer.getValueString(a_obj)) ;
+ }
+ l_buf.append('\'') ;
+
+ return l_buf.toString() ;
+ }
+
+
+ /**
+ * Gets the value of a record by key if the key exists. If this Table
+ * allows duplicate keys then the first key will be returned. If this
+ * Table is also a Btree that first key will be the smallest key in the
+ * Table as specificed by this Table's comparator or the default berkeley
+ * bytewise lexical comparator.
+ *
+ * @param a_key the key of the record
+ * @return the value of the Btree tuple which is a TreeSet if this Table
+ * supports duplicates.
+ * @throws BackendException if there is a failure to read the underlying Db
+ */
+ private Object getRaw(Object a_key)
+ throws BackendException
+ {
+ Object l_value = null ;
+
+ try {
+ l_value = m_bt.find(a_key) ;
+ } catch(IOException e) {
+ throw new BackendException("Failed to get value for key "
+ + renderKey(a_key) + ":\n"
+ + ExceptionUtil.printStackTrace(e), e) ;
+ }
+
+ return l_value ;
+ }
+
+
+ private Object putRaw(Object a_key, Object a_value, boolean doReplace)
+ throws BackendException
+ {
+ Object l_replaced = null ;
+
+ try {
+ l_replaced = m_bt.insert(a_key, a_value, doReplace) ;
+ } catch(IOException e) {
+ throw new BackendException("Failed to insert key value pair "
+ + render(a_key, a_value) + " into table:\n"
+ + ExceptionUtil.printStackTrace(e), e) ;
+ }
+
+ return l_replaced ;
+ }
+
+
+ private Object removeRaw(Object a_key)
+ throws BackendException
+ {
+ Object l_removed = null ;
+
+ try {
+ l_removed = m_bt.remove(a_key) ;
+ } catch(IOException e) {
+ throw new BackendException(
+ "Failed to remove record with key " + renderKey(a_key)
+ + ":\n" + ExceptionUtil.printStackTrace(e), e) ;
+ }
+
+ return l_removed ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/table/KeyOnlyComparator.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/table/KeyOnlyComparator.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,78 @@
+/*
+ * $Id: KeyOnlyComparator.java,v 1.2 2003/03/13 18:27:32 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm.table ;
+
+
+public class KeyOnlyComparator
+ implements TupleComparator
+{
+ TableComparator m_keyComparator = null ;
+
+
+ public KeyOnlyComparator(TableComparator a_comparator)
+ {
+ m_keyComparator = a_comparator ;
+ }
+
+
+ /**
+ * Gets the comparator used to compare keys. May be null in which
+ * case the compareKey method will throw an UnsupportedOperationException.
+ *
+ * @return the comparator for comparing keys.
+ */
+ public TableComparator getKeyComparator()
+ {
+ return m_keyComparator ;
+ }
+
+
+ /**
+ * Will throw an UnsupportedOperationException every time.
+ *
+ * @throws UnsuporredOperation every time.
+ */
+ public TableComparator getValueComparator()
+ {
+ throw new UnsupportedOperationException() ;
+ }
+
+
+ /**
+ * Compares key Object to determine their sorting order returning a
+ * value = to, < or > than 0.
+ *
+ * @param a_key1 the first key to compare
+ * @param a_key2 the other key to compare to the first
+ * @return 0 if both are equal, a negative value less than 0 if the first
+ * is less than the second, or a postive value if the first is greater than
+ * the second byte array.
+ */
+ public int compareKey(Object a_key1, Object a_key2)
+ {
+ return m_keyComparator.compare(a_key1, a_key2) ;
+ }
+
+
+ /**
+ * Comparse value Objects to determine their sorting order returning a
+ * value = to, < or > than 0.
+ *
+ * @param a_value1 the first value to compare
+ * @param a_value2 the other value to compare to the first
+ * @return 0 if both are equal, a negative value less than 0 if the first
+ * is less than the second, or a postive value if the first is greater than
+ * the second Object.
+ */
+ public int compareValue(Object a_value1, Object a_value2)
+ {
+ throw new UnsupportedOperationException() ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/table/MasterTable.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/table/MasterTable.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,189 @@
+/*
+ * $Id: MasterTable.java,v 1.3 2003/03/13 18:27:33 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm.table ;
+
+
+import java.io.File ;
+import java.math.BigInteger ;
+import javax.naming.NamingException ;
+
+import org.apache.eve.backend.BackendException ;
+import jdbm.recman.RecordManager;
+import org.apache.eve.backend.jdbm.index.BigIntegerComparator;
+import org.apache.eve.backend.jdbm.index.StringComparator;
+import org.apache.eve.backend.jdbm.index.IndexComparator;
+
+
+/**
+ * The master table used to store LDIF based entries.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.3 $
+ * @testcase org.apache.eve.backend.berkeley.table.TestMasterTable
+ */
+public class MasterTable
+ extends JdbmTable
+{
+ /** the name of the dbf file for this table */
+ public static final String DBF = "master" ;
+ /** the sequence key - stores last sequence value in the admin table */
+ public static final String m_sequence = "__sequence__" ;
+
+ private JdbmTable m_adminTbl = null ;
+
+
+ /**
+ * Creates the master entry table using a Berkeley Db for the backing store.
+ *
+ * @param a_wkdirPath the working directory path where we create the
+ * berkeley database files.
+ * @throws BackendException if there is an error opening the Db file.
+ */
+ public MasterTable(RecordManager a_recMan)
+ throws BackendException
+ {
+ super(DBF, a_recMan, new BigIntegerComparator()) ;
+ m_adminTbl = new JdbmTable("admin", a_recMan, IndexComparator.strComp) ;
+ String l_seqValue = (String) m_adminTbl.get(m_sequence) ;
+ if(null == l_seqValue) {
+ m_adminTbl.put(m_sequence, BigInteger.ZERO.toString()) ;
+ }
+ }
+
+
+ /**
+ * Gets an LDIF record out of this MasterTable corresponding to an entry
+ * with a id.
+ *
+ * @param an_id the BigInteger id of the entry to retrieve.
+ * @return the LDIF of the entry with operational attributes and all.
+ * @throws BackendException if there is a read error on the underlying Db.
+ */
+ public String get(BigInteger an_id)
+ throws BackendException
+ {
+ return (String) super.get(an_id) ;
+ }
+
+
+ /**
+ * Puts a ldif into the master table at an index specified by an_id. This
+ * is used both to create new entries and update existing ones.
+ *
+ * @param a_ldif the LDIF of the entry with operational attributes and all.
+ * @param an_id the BigInteger id of the entry to put.
+ * @throws BackendException if there is a write error on the underlying Db.
+ */
+ public String put(String a_ldif, BigInteger an_id)
+ throws BackendException
+ {
+ return (String) super.put(an_id, a_ldif) ;
+ }
+
+
+ /**
+ * Deletes a entry from the master table at an index specified by an_id.
+ *
+ * @param an_id the BigInteger id of the entry to delete.
+ * @throws BackendException if there is a write error on the underlying Db.
+ */
+ public String del(BigInteger an_id)
+ throws BackendException, NamingException
+ {
+ return (String) super.remove(an_id) ;
+ }
+
+
+ /**
+ * Get's the current id value from this master database's sequence without
+ * affecting the seq.
+ *
+ * @return the current value.
+ * @throws BackendException if the admin table storing sequences cannot be
+ * read.
+ */
+ public BigInteger getCurrentId()
+ throws BackendException
+ {
+ BigInteger l_id = null ;
+
+ synchronized(m_adminTbl) {
+ l_id = new BigInteger((String) m_adminTbl.get(m_sequence)) ;
+ if(null == l_id) {
+ m_adminTbl.put(m_sequence, BigInteger.ZERO.toString()) ;
+ l_id = BigInteger.ZERO ;
+ }
+ }
+
+ return l_id ;
+ }
+
+
+ /**
+ * Get's the next value from this SequenceBDb. This has the side-effect of
+ * changing the current sequence values perminantly in memory and on disk.
+ *
+ * @return the current value incremented by one.
+ * @throws BackendException if the admin table storing sequences cannot be
+ * read and writen to.
+ */
+ public BigInteger getNextId()
+ throws BackendException
+ {
+ BigInteger l_lastVal = null ;
+ BigInteger l_nextVal = null ;
+
+ synchronized(m_adminTbl) {
+ l_lastVal = new BigInteger((String) m_adminTbl.get(m_sequence)) ;
+ if(null == l_lastVal) {
+ m_adminTbl.put(m_sequence, BigInteger.ONE.toString()) ;
+ return BigInteger.ONE ;
+ } else {
+ l_nextVal = l_lastVal.add(BigInteger.ONE) ;
+ m_adminTbl.put(m_sequence, l_nextVal.toString()) ;
+ }
+ }
+
+ return (l_nextVal) ;
+ }
+
+
+ /**
+ * Gets a persistant property stored in the admin table of this MasterTable.
+ *
+ * @param a_property the key of the property to get the value of
+ * @return the value of the property
+ * @throws BackendException when the underlying admin table cannot be read
+ */
+ public String getProperty(String a_property)
+ throws BackendException
+ {
+ synchronized(m_adminTbl) {
+ return (String) m_adminTbl.get(a_property) ;
+ }
+ }
+
+
+ /**
+ * Sets a persistant property stored in the admin table of this MasterTable.
+ *
+ * @param a_property the key of the property to set the value of
+ * @param a_value the value of the property
+ * @throws BackendException when the underlying admin table cannot be writen
+ */
+ public void setProperty(String a_property, String a_value)
+ throws BackendException
+ {
+ synchronized(m_adminTbl) {
+ m_adminTbl.put(a_property, a_value) ;
+ }
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/table/NoDupsCursor.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/table/NoDupsCursor.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,108 @@
+/*
+ * $Id: NoDupsCursor.java,v 1.3 2003/03/13 18:27:33 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm.table ;
+
+
+import org.apache.eve.backend.Cursor ;
+import org.apache.eve.backend.BackendException ;
+
+import jdbm.helper.TupleBrowser ;
+import jdbm.helper.Tuple;
+import java.io.IOException ;
+import javax.naming.NamingException ;
+
+import org.apache.avalon.framework.ExceptionUtil ;
+
+
+/**
+ * A simple cursor over a TupleBrowser on a table that does not allow
+ * duplicates.
+ *
+ * @warning The Tuple returned by this Cursor is always the same instance object
+ * returned every time. It is reused to for the sake of efficency rather than
+ * creating a new tuple for each advance() call.
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.3 $
+ */
+public class NoDupsCursor
+ extends Cursor
+{
+ private final Tuple m_returned = new Tuple() ;
+ private final Tuple m_prefetched = new Tuple() ;
+ private final TupleBrowser m_browser ;
+ private final boolean doAscendingScan ;
+
+ protected boolean canAdvance = true ;
+
+
+ /**
+ * Creates a cursor over a TupleBrowser where duplicates are not expected.
+ */
+ NoDupsCursor(TupleBrowser a_browser, boolean doAscendingScan)
+ throws BackendException
+ {
+ m_browser = a_browser ;
+ this.doAscendingScan = doAscendingScan ;
+ prefetch() ;
+ }
+
+
+ boolean doAscendingScan()
+ {
+ return this.doAscendingScan ;
+ }
+
+
+ void prefetch()
+ throws BackendException
+ {
+ // Prefetch into tuple!
+ boolean isSuccess = false ;
+
+ try {
+ if(doAscendingScan) {
+ isSuccess = m_browser.getNext(m_prefetched) ;
+ } else {
+ isSuccess = m_browser.getPrevious(m_prefetched) ;
+ }
+ } catch(IOException e) {
+ throw new BackendException("Could not advance cursor due to "
+ + " TupleBrowser failure:\n"
+ + ExceptionUtil.printStackTrace(e)) ;
+ }
+
+ if(!isSuccess) {
+ canAdvance = false ;
+ try { close() ; } catch(NamingException e) { /* Never thrown */ }
+ }
+ }
+
+
+ protected Object advance()
+ throws BackendException
+ {
+ m_returned.setKey(m_prefetched.getKey()) ;
+ m_returned.setValue(m_prefetched.getValue()) ;
+
+ prefetch() ;
+
+ return m_returned ;
+ }
+
+
+ protected boolean canAdvance()
+ {
+ return canAdvance ;
+ }
+
+
+ public void freeResources() { /* Does nothing! */ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/table/Table.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/table/Table.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,288 @@
+/*
+ * $Id: Table.java,v 1.2 2003/03/13 18:27:34 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm.table ;
+
+
+import org.apache.eve.backend.Cursor ;
+import org.apache.eve.backend.BackendException ;
+
+
+/**
+ * A backend friendly wrapper around a jdbm BTree that transparent enables
+ * duplicates when the BTree does not support them.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.2 $
+ */
+public interface Table
+{
+ /**
+ * Gets the comparator used by this Table: may be null if this Table was
+ * not initialized with one.
+ *
+ * @return the final comparator instance or null if this Table was not
+ * created with one.
+ */
+ public TupleComparator getComparator() ;
+
+ /**
+ * Gets the data renderer used by this Table to display or log records keys
+ * and values.
+ *
+ * @return the renderer used
+ */
+ public TupleRenderer getRenderer() ;
+
+ /**
+ * Sets the data renderer to by used by this Table to display or log record
+ * keys and values.
+ *
+ * @param a_renderer the DataRenderer instance to used as the renderer.
+ */
+ public void setRenderer(TupleRenderer a_renderer) ;
+
+ /**
+ * Gets the name of this Table.
+ *
+ * @return the name
+ */
+ public String getName() ;
+
+ /**
+ * Checks to see if this Table has enabled the use of duplicate keys.
+ *
+ * @return true if duplicate keys are enabled, false otherwise.
+ */
+ public boolean isDupsEnabled() ;
+
+ /**
+ * Checks to see if this Table has enabled sorting on the values of
+ * duplicate keys.
+ *
+ * @return true if duplicate key values are sorted, false otherwise.
+ */
+ public boolean isSortedDupsEnabled() ;
+
+ ///////////////////////////////////////
+ // Simple Table Key/Value Assertions //
+ ///////////////////////////////////////
+
+ /**
+ * Checks to see if this table has a key: same as a get call with a check to
+ * see if the returned value is null or not.
+ *
+ * @param a_key the Object of the key to check for
+ * @return true if the key exists, false otherwise.
+ * @throws BackendException if there is a failure to read the underlying Db
+ */
+ public boolean has(Object a_key) throws BackendException ;
+
+ /**
+ * Checks to see if this table has a key with a specific value.
+ *
+ * @param a_key the key Object to check for
+ * @param a_value the value Object to check for
+ * @return true if a record with the key and value exists, false otherwise.
+ * @throws BackendException if there is a failure to read the underlying Db
+ */
+ public boolean has(Object a_key, Object a_value) throws BackendException ;
+
+ /**
+ * Checks to see if this table has a record with a key greater/less than or
+ * equal to the key argument. The key argument need not exist for this
+ * call to return true. The underlying database must be a BTree because
+ * this method depends on the use of sorted keys.
+ *
+ * @param a_key the key Object to compare keys to
+ * @param isGreaterThan boolean for greater than or less then comparison
+ * @return true if a record with a key greater/less than the key argument
+ * exists, false otherwise
+ * @throws BackendException if there is a failure to read the underlying Db,
+ * or if the underlying Db is not a Btree.
+ */
+ public boolean has(Object a_key, boolean isGreaterThan)
+ throws BackendException ;
+
+ /**
+ * Checks to see if this table has a record with a key equal to the
+ * argument key with a value greater/less than or equal to the value
+ * argument provided. The key argument <strong>MUST</strong> exist for
+ * this call to return true and the underlying Db must be a Btree that
+ * allows for sorted duplicate values. The entire basis to this method
+ * depends on the fact that duplicate key values are sorted according to
+ * a valid value comparator function.
+ *
+ * @param a_key the key Object
+ * @param a_val the value Object to compare values to
+ * @param isGreaterThan boolean for greater than or less then comparison
+ * @return true if a record with a key greater/less than the key argument
+ * exists, false otherwise
+ * @throws BackendException if there is a failure to read the underlying Db
+ * or if the underlying Db is not of the Btree type that allows sorted
+ * duplicate values.
+ */
+ public boolean has(Object a_key, Object a_val, boolean isGreaterThan)
+ throws BackendException ;
+
+ ////////////////////////////////////
+ // Table Value Accessors/Mutators //
+ ////////////////////////////////////
+
+ /**
+ * Gets the value of a record by key if the key exists. If this Table
+ * allows duplicate keys then the first key will be returned. If this
+ * Table is also a Btree that first key will be the smallest key in the
+ * Table as specificed by this Table's comparator or the default berkeley
+ * bytewise lexical comparator.
+ *
+ * @param a_key the key of the record
+ * @return the value of the record with a_key if a_key exists or null if
+ * no such record exists.
+ * @throws BackendException if there is a failure to read the underlying Db
+ */
+ public Object get(Object a_key) throws BackendException ;
+
+ /**
+ * Puts a record into this Table.
+ *
+ * @param a_key the key of the record
+ * @param a_value the value of the record.
+ * @return the last value present for a_key or null if this the key did not
+ * exist before.
+ * @throws BackendException if there is a failure to read or write to
+ * the underlying Db
+ */
+ public Object put(Object a_key, Object a_value) throws BackendException ;
+
+ /**
+ * Removes all records with a_key from this Table.
+ *
+ * @param the key of the records to remove.
+ * @throws BackendException if there is a failure to read or write to
+ * the underlying Db
+ */
+ public Object remove(Object a_key) throws BackendException ;
+
+ /**
+ * Removes a single specific record with a_key and a_value from this Table.
+ *
+ * @param the key of the record to remove.
+ * @param the value of the record to remove.
+ * @throws BackendException if there is a failure to read or write to
+ * the underlying Db
+ */
+ public Object remove(Object a_key, Object a_value) throws BackendException ;
+
+ //////////////////////
+ // Cursor Overloads //
+ //////////////////////
+
+ /**
+ * Sets a cursor to the first record in the Table and enables single
+ * next steps across all records.
+ *
+ * @throws BackendException if the underlying cursor could not be set.
+ */
+ public Cursor getCursor() throws BackendException ;
+
+ /**
+ * Sets a cursor to the first record in the Table with a key value of
+ * a_key and enables single next steps across all duplicate records with
+ * this key. This cursor will only iterate over duplicates of the key.
+ *
+ * @param a_key the key to iterate over
+ * @throws BackendException if the underlying cursor could not be set
+ */
+ public Cursor getCursor(Object a_key) throws BackendException ;
+
+ /**
+ * Sets a cursor to the first record in the Table with a key value
+ * greater/less than or equal to a_key and enables single next steps across
+ * all records with key values equal to or less/greater than a_key.
+ *
+ * @warning This cursor operation has no meaning for database table
+ * types other than the btree type since it relies on sorted keys.
+ * @param a_key the key to use to position this cursor to record with a key
+ * greater/less than or equal to it.
+ * @param isGreaterThan if true the cursor iterates up over ascending keys
+ * greater than or equal to the a_key argument, but if false this cursor
+ * iterates down over descending keys less than or equal to a_key argument.
+ * @throws BackendException if the underlying cursor could not be set
+ */
+ public Cursor getCursor(Object a_key, boolean isGreaterThan)
+ throws BackendException ;
+
+ /**
+ * Sets a cursor to the first record in the Table with a key equal to
+ * the a_key argument whose value is greater/less than or equal to a_key and
+ * enables single next steps across all records with key equal to a_key.
+ * Hence this cursor will only iterate over duplicate keys where values are
+ * less than or greater than or equal to a_val.
+ *
+ * @warning the underlying Db must have sorted duplicates enabled as in an
+ * Index.
+ * @param a_key the key to use to position this cursor to record with a key
+ * equal to it.
+ * @param a_val the value to use to position this cursor to record with a
+ * value greater/less than or equal to it.
+ * @param isGreaterThan if true the cursor iterates up over ascending values
+ * greater than or equal to the a_val argument, but if false this cursor
+ * iterates down over descending values less than or equal to a_val argument
+ * starting from the largest value going down.
+ * @throws BackendException if the underlying cursor could not be set or
+ * this method is called over a cursor on a table that does not have sorted
+ * duplicates enabled.
+ */
+ public Cursor getCursor(Object a_key, Object a_val, boolean isGreaterThan)
+ throws BackendException ;
+
+ ////////////////////////////////
+ // Table Record Count Methods //
+ ////////////////////////////////
+
+ /**
+ * Gets the count of the number of records in this Table.
+ *
+ * @return the number of records
+ * @throws BackendException if there is a failure to read the underlying Db
+ */
+ public int count() throws BackendException ;
+
+ /**
+ * Gets the count of the number of records in this Table with a specific
+ * key: returns the number of duplicates for a key.
+ *
+ * @param a_key the Object key to count.
+ * @return the number of duplicate records for a key.
+ * @throws BackendException if there is a failure to read the underlying Db
+ */
+ public int count(Object a_key) throws BackendException ;
+
+ /**
+ * Returns the number of records greater than or less than a key value. The
+ * key need not exist for this call to return a non-zero value.
+ *
+ * @param a_key the Object key to count.
+ * @param isGreaterThan boolean set to true to count for greater than and
+ * equal to record keys, or false for less than or equal to keys.
+ * @return the number of keys greater or less than a_key.
+ * @throws BackendException if there is a failure to read the underlying Db
+ */
+ public int count(Object a_key, boolean isGreaterThan) throws BackendException ;
+
+ /**
+ * Closes the underlying Db of this Table.
+ *
+ * @throws BackendException if there is a failure to close the handle to
+ * the underlying Db file.
+ */
+ public void close() ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/table/TableComparator.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/table/TableComparator.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,26 @@
+/*
+ * $Id: TableComparator.java,v 1.2 2003/03/13 18:27:34 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm.table ;
+
+
+/**
+ * Doc me!
+ * @todo Doc me!
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.2 $
+ */
+public abstract class TableComparator
+ extends jdbm.helper.Comparator
+ implements java.util.Comparator
+{
+ public abstract int compare( Object an_obj1, Object an_obj2 ) ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/table/TupleComparator.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/table/TupleComparator.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,64 @@
+/*
+ * $Id: TupleComparator.java,v 1.3 2003/03/13 18:27:34 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm.table ;
+
+
+/**
+ * Used to compare the sorting order of binary data.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.3 $
+ */
+public interface TupleComparator
+{
+ /**
+ * Gets the comparator used to compare keys. May be null in which
+ * case the compareKey method will throw an UnsupportedOperationException.
+ *
+ * @return the comparator for comparing keys.
+ */
+ TableComparator getKeyComparator() ;
+
+
+ /**
+ * Gets the binary comparator used to compare valuess. May be null in which
+ * case the compareValue method will throw an UnsupportedOperationException.
+ *
+ * @return the binary comparator for comparing values.
+ */
+ TableComparator getValueComparator() ;
+
+
+ /**
+ * Compares key Object to determine their sorting order returning a
+ * value = to, < or > than 0.
+ *
+ * @param a_key1 the first key to compare
+ * @param a_key2 the other key to compare to the first
+ * @return 0 if both are equal, a negative value less than 0 if the first
+ * is less than the second, or a postive value if the first is greater than
+ * the second byte array.
+ */
+ int compareKey(Object a_key1, Object a_key2) ;
+
+
+ /**
+ * Comparse value Objects to determine their sorting order returning a
+ * value = to, < or > than 0.
+ *
+ * @param a_value1 the first value to compare
+ * @param a_value2 the other value to compare to the first
+ * @return 0 if both are equal, a negative value less than 0 if the first
+ * is less than the second, or a postive value if the first is greater than
+ * the second Object.
+ */
+ int compareValue(Object a_value1, Object a_value2) ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/table/TupleIteratorCursor.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/table/TupleIteratorCursor.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,64 @@
+/*
+ * $Id: TupleIteratorCursor.java,v 1.2 2003/03/13 18:27:35 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm.table ;
+
+
+import java.util.Iterator ;
+import org.apache.eve.backend.Cursor;
+import jdbm.helper.Tuple;
+
+
+/**
+ * A cursor using an underlying Iterator.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.2 $
+ */
+public class TupleIteratorCursor
+ extends Cursor
+{
+ private final Object m_key ;
+ private final Iterator m_iterator ;
+ private final Tuple m_tuple = new Tuple() ;
+
+
+ /**
+ * Creates a cursor over an Iterator.
+ *
+ * @param a_iterator the underlying iterator this cursor uses.
+ */
+ public TupleIteratorCursor(Object a_key, Iterator a_iterator)
+ {
+ m_key = a_key ;
+ m_tuple.setKey(a_key) ;
+ m_iterator = a_iterator ;
+ }
+
+
+ /** Returns iterator.next() */
+ public Object advance()
+ {
+ m_tuple.setKey(m_key) ;
+ m_tuple.setValue(m_iterator.next()) ;
+ return m_tuple ;
+ }
+
+
+ /** Returns iterator.hasNext() */
+ public boolean canAdvance()
+ {
+ return m_iterator.hasNext() ;
+ }
+
+
+ /** Does nothing */
+ public void freeResources() { }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/table/TupleRenderer.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/jdbm/table/TupleRenderer.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,45 @@
+/*
+ * $Id: TupleRenderer.java,v 1.2 2003/03/13 18:27:35 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.backend.jdbm.table ;
+
+
+import org.apache.eve.backend.BackendException ;
+
+
+/**
+ * A table key/value String renderer for the display or logging of
+ * human readable potentially binary data.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.2 $
+ */
+public interface TupleRenderer
+{
+ /**
+ * Gets the key Object rendered as a String.
+ *
+ * @param a_key the key Object
+ * @return the String representation of the key Object
+ * @throws BackendException if there is a backend failure while trying to
+ * interpret the key.
+ */
+ String getKeyString(Object a_key) ;
+
+ /**
+ * Gets the value Object rendered as a String.
+ *
+ * @param a_value the value Object
+ * @return the String representation of the value Object
+ * @throws BackendException if there is a backend failure while trying to
+ * interpret the value.
+ */
+ String getValueString(Object a_value) ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/package.html
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/backend/package.html Thu Jun 24 00:06:35 2004
@@ -0,0 +1,4 @@
+
+<p><font color="#999999">$Id: package.html,v 1.1.1.1 2002/11/13 23:46:12 akarasulu Exp $</font> </p>
+<p>The backend package defines interfaces that must be implemented by all Backend
+ modules. </p>
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/client/ClientException.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/client/ClientException.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,38 @@
+/*
+ * $Id: ClientException.java,v 1.2 2003/03/13 18:27:03 akarasulu Exp $
+ * $Prologue$
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.client ;
+
+
+import org.apache.avalon.framework.CascadingRuntimeException ;
+
+
+/** This exception is thrown when protocol errors occurred */
+public class ClientException extends CascadingRuntimeException
+{
+ /**
+ * Constructs an Exception with a detailed message.
+ * @param Message The message associated with the exception.
+ */
+ public ClientException(String message, Throwable t)
+ {
+ super(message, t) ;
+ }
+
+
+ /**
+ * Constructs an Exception with a detailed message.
+ * @param Message The message associated with the exception.
+ */
+ public ClientException(String message)
+ {
+ super(message, null) ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/client/ClientKey.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/client/ClientKey.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,286 @@
+/*
+ * $Id: ClientKey.java,v 1.5 2003/08/22 21:15:55 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.client ;
+
+
+import java.net.Socket ;
+import java.net.InetAddress ;
+
+
+/**
+ * Every client that successfully binds anonymously or with a valid identity
+ * has a unique client key represented by this class. First and foremost the
+ * key is used to uniquely identify the client based on the interface and
+ * port used to connection on the server as well as the interface and port used
+ * by the client.
+ *
+ * The ClientKey plays a central role in coordinating activities with the
+ * server across various threads. Threads within the same stage or across
+ * stages are synchronized on client resources using lock objects held by a
+ * ClientKey instance. Socket IO is managed using a pair of lock objects
+ * specificially for this purpose. As the need arises more lock objects may be
+ * used for specific client resources like a session object. These extra lock
+ * objects are now being discussed.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.5 $
+ */
+public final class ClientKey
+{
+ // ----------------------------------------------
+ // Private members.
+ // ----------------------------------------------
+
+ /** Input channel synchronization object */
+ private final Object m_inputLock = new Object() ;
+ /** Output channel synchronization object */
+ private final Object m_outputLock = new Object() ;
+ /** Server socket interface address */
+ private final InetAddress m_serverAddress ;
+ /** Client socket interface address */
+ private final InetAddress m_clientAddress ;
+ /** Whether or not this key has expired: the client has disconnected. */
+ private boolean m_hasExpired = false ;
+
+ // ----------------------------------------------
+ // pkg-friendly final members: made so the public
+ // accessors do not need to be used by classes in
+ // this pkg - need access to these members for
+ // cleanup operations after expiration. Do not
+ // want to unnecessarily throw an exception.
+ // ----------------------------------------------
+
+ /** Unique key or client id */
+ final String m_clientId ;
+ /** Server socket TCP port on server host */
+ final int m_serverPort ;
+ /** Client socket TCP port on client host */
+ final int m_clientPort ;
+
+
+ // ----------------------------------------------
+ // Constructors
+ // ----------------------------------------------
+
+
+ /**
+ * Generates a unique connection/client identifier String for a client
+ * socket connection. The key is composed of the local server address
+ * and port attached to the remote client address and port. If the
+ * server ip and port are 192.168.1.1:1389 and the client's ip and port are
+ * 34.23.12.1:5678 then the key string would be:
+ *
+ * 192.168.1.1:1389<-34.23.12.1:5678
+ *
+ * This makes the key unique at any single point in time.
+ *
+ * @param a_socket newly established client socket connection to the
+ * server.
+ */
+ ClientKey( final Socket a_socket )
+ {
+ // Extract properties needed to formulate the client id ( key ).
+ m_serverPort = a_socket.getLocalPort() ;
+ m_serverAddress = a_socket.getLocalAddress() ;
+ m_clientPort = a_socket.getPort() ;
+ m_clientAddress = a_socket.getInetAddress() ;
+
+ // Build the key
+ StringBuffer l_buf =
+ new StringBuffer(m_serverAddress.getHostAddress()) ;
+ l_buf.append(':').append(m_serverPort).append("<-") ;
+ l_buf.append(m_clientAddress.getHostAddress()).append(':') ;
+ l_buf.append(m_clientPort) ;
+ m_clientId = l_buf.toString() ;
+ }
+
+
+ // ----------------------------------------------
+ // Accessors of conn. parameters to client id
+ // ----------------------------------------------
+
+
+ /**
+ * Get the unique client id for a connected client based on connection
+ * parameters.
+ *
+ * @return the unique id of the client connection
+ * @throws KeyExpiryException to force the handling of expired keys rather
+ * than depending on developers to maintain a convention of checking for
+ * key expiration before use in other modules.
+ */
+ public String getClientId()
+ throws KeyExpiryException
+ {
+ checkExpiry() ;
+ return m_clientId ;
+ }
+
+
+ /**
+ * Gets the client's IP address.
+ *
+ * @return the client's ip address.
+ * @throws KeyExpiryException to force the handling of expired keys
+ */
+ public String getClientAddress()
+ throws KeyExpiryException
+ {
+ checkExpiry() ;
+ return m_clientAddress.getHostAddress() ;
+ }
+
+
+ /**
+ * Gets the client's hostname.
+ *
+ * @return the client's hostname.
+ * @throws KeyExpiryException to force the handling of expired keys
+ */
+ public String getClientHost()
+ throws KeyExpiryException
+ {
+ checkExpiry() ;
+ return m_clientAddress.getHostName() ;
+ }
+
+
+ // ----------------------------------------------
+ // ClientKey lock object accessors.
+ // ----------------------------------------------
+
+
+ /**
+ * Gets the client's output stream lock object.
+ *
+ * @return ouput lock object.
+ * @throws KeyExpiryException to force the handling of expired keys
+ */
+ public Object getOutputLock()
+ throws KeyExpiryException
+ {
+ checkExpiry() ;
+ return m_outputLock ;
+ }
+
+
+ /**
+ * Gets the client's input stream lock object.
+ *
+ * @return input lock object.
+ * @throws KeyExpiryException to force the handling of expired keys
+ */
+ public Object getInputLock()
+ throws KeyExpiryException
+ {
+ checkExpiry() ;
+ return m_inputLock ;
+ }
+
+
+ // ----------------------------------------------
+ // Key expiration methods.
+ // ----------------------------------------------
+
+
+ /**
+ * Determines if the client represented by this ClientKey is still
+ * connected to the server. Once disconnected the ClientKey is expired
+ * by the server so processing on behalf of the client does not continue.
+ *
+ * @return true if the client is no longer connected to the server, false
+ * if the client is connected.
+ */
+ public boolean hasExpired()
+ {
+ return m_hasExpired ;
+ }
+
+
+ /**
+ * Expires this key to indicate the disconnection of the client represented
+ * by this key from the server. It is intentionally package friendly to
+ * only allow access by the ClientModule.
+ */
+ void expire()
+ {
+ m_hasExpired = true ;
+ }
+
+
+ /**
+ * Utility method to throw key expiration exception if this ClientKey has
+ * expired. This method is called by most accessor methods within this
+ * class with <code>hasExpired()</code> being the only exception. The
+ * purpose for this is to force ClientKey using modules to check for
+ * expiration rather rely upon them to check to see if the key is valid
+ * before use everytime.
+ *
+ * @throws KeyExpiryException to force the handling of expired keys rather
+ * than depending on developers to maintain a convention of checking for
+ * key expiration before use in other modules.
+ */
+ private void checkExpiry()
+ throws KeyExpiryException
+ {
+ if(m_hasExpired) {
+ throw new KeyExpiryException() ;
+ }
+ }
+
+
+ // ----------------------------------------------
+ // Class java.lang.Object method overrides.
+ // ----------------------------------------------
+
+
+ /**
+ * For debugging returns the clientId string.
+ *
+ * @return the client id string.
+ */
+ public String toString()
+ {
+ return m_clientId ;
+ }
+
+
+ /**
+ * Gets the hashCode of the unique clientId String. Overriden to correctly
+ * manage ClientKey's within Map based collections.
+ *
+ * @return the clientId hashCode value.
+ */
+ public int hashCode()
+ {
+ return m_clientId.hashCode() ;
+ }
+
+
+ /**
+ * Determines whether this ClientKey is equivalent to another. If argument
+ * object is not the same reference the clientId String's are compared using
+ * the <code>String.equal()</code> method. Required for containment within
+ * collections.
+ *
+ * @return true if an_obj equals this ClientKey, false otherwise.
+ */
+ public boolean equals(Object an_obj)
+ {
+ if(this == an_obj) {
+ return true ;
+ } else if(an_obj instanceof ClientKey) {
+ return ((ClientKey) an_obj).m_clientId.equals(m_clientId) ;
+ }
+
+ return false ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/client/ClientManager.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/client/ClientManager.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,123 @@
+/*
+ * $Id: ClientManager.java,v 1.7 2003/08/22 21:15:55 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.client ;
+
+
+import java.net.Socket ;
+import java.io.IOException ;
+import java.io.InputStream ;
+
+import org.apache.eve.event.OutputListener ;
+import org.apache.eve.event.ConnectListener ;
+import org.apache.eve.security.LdapPrincipal ;
+import javax.naming.ldap.LdapContext;
+
+
+/**
+ * Service interface used to manage clients, their connections and their
+ * stateful sessions.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.7 $
+ */
+public interface ClientManager
+ extends ConnectListener
+{
+ /** role played by this service interface */
+ String ROLE = ClientManager.class.getName() ;
+
+ /**
+ * Drops a client connection and destroys the client's session.
+ *
+ * @param a_clientKey the key used to uniquely identify this client.
+ */
+ void drop( ClientKey a_clientKey ) ;
+
+ /**
+ * Drops a client connection and destroys the client's session associated
+ * with the calling thread.
+ */
+ void drop() ;
+
+ /**
+ * Creates a client session using the client's unique key.
+ *
+ * @param a_clientKey the client key used to uniquely identify the client.
+ * @param a_socket a client socket to the server.
+ */
+ ClientSession add( ClientKey a_clientKey, Socket a_socket )
+ throws IOException ;
+
+ /**
+ * Sets the user principal for a client on a bind operation. The protocol
+ * states that a bind operation requires the destruction of all outstanding
+ * operations. Hence all outstanding operations refered to by the client's
+ * key must be terminated, the session parameters are flushed, then the
+ * princal is set. The client affectively changes its role without dropping
+ * the socket connection.
+ *
+ * @param a_clientKey the client's unique key.
+ * @param a_principal the new principal to be taken on by the client using
+ * the existing socket connection.
+ */
+ ClientSession
+ setUserPrincipal( ClientKey a_clientKey, LdapPrincipal a_principal ) ;
+
+ /**
+ * Explicit access to a client's session by the client's ClientKey.
+ *
+ * @param a_clientKey the client's unique key
+ * @return the session associated with the client's key.
+ */
+ ClientSession getClientSession( ClientKey a_clientKey ) ;
+
+ /**
+ * Gets the client session associated with the calling thread's context.
+ *
+ * @return the client's session which the current thread is doing work for.
+ */
+ ClientSession getClientSession() ;
+
+ /**
+ * Gets the key of the client on whose behalf the current thread is
+ * executing.
+ *
+ * @return the ClientKey associated with the callers thread or null if none
+ * exists.
+ */
+ ClientKey getClientKey() ;
+
+ /**
+ * Gets the LdapContext associated with the calling thread.
+ *
+ * @return the context of the caller thread
+ */
+ LdapContext getLdapContext() ;
+
+ /**
+ * Associates an external thread using the JNDI provider with a LdapContext.
+ *
+ * @param a_ctx the LdapContext to be associated with the calling thread.
+ */
+ void threadAssociate( LdapContext a_ctx ) ;
+
+ /**
+ * Associates a protocol request handler driving thread with a client.
+ *
+ * @param a_clientKey the unique ClientKey associated with the request.
+ */
+ void threadAssociate( ClientKey a_clientKey ) ;
+
+ /**
+ * Disassociates a protocol request handler driving thread with a client.
+ */
+ void threadDisassociate() ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/client/ClientManagerSlave.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/client/ClientManagerSlave.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,15 @@
+/*
+ * $Id: ClientManagerSlave.java,v 1.2 2003/03/13 18:27:04 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.client ;
+
+public interface ClientManagerSlave
+{
+ void registerClientManager(ClientManager a_clientManager) ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/client/ClientModule.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/client/ClientModule.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,509 @@
+/*
+ * $Id: ClientModule.java,v 1.13 2003/08/22 21:15:55 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.client ;
+
+
+import java.util.Map ;
+import java.util.HashMap ;
+import java.util.EventObject ;
+
+import java.net.Socket ;
+
+import java.io.IOException ;
+import java.io.InputStream ;
+import java.io.OutputStream ;
+import java.io.PushbackInputStream ;
+import java.io.BufferedOutputStream ;
+
+import org.apache.eve.decoder.Decoder ;
+import org.apache.eve.event.InputEvent ;
+import org.apache.eve.event.OutputEvent ;
+import org.apache.eve.input.InputModule ;
+import org.apache.eve.seda.AbstractStage ;
+import org.apache.eve.event.ConnectEvent ;
+import org.apache.eve.event.EventHandler ;
+import org.apache.eve.input.InputManager ;
+import org.apache.eve.output.OutputModule ;
+import org.apache.eve.output.OutputManager ;
+import org.apache.eve.security.LdapPrincipal ;
+import org.apache.eve.backend.UnifiedBackend ;
+import org.apache.eve.protocol.ProtocolEngine ;
+import org.apache.eve.event.AbstractEventHandler ;
+
+import org.apache.avalon.framework.logger.Logger ;
+import org.apache.avalon.framework.service.ServiceManager ;
+import org.apache.avalon.framework.service.ServiceException ;
+import org.apache.avalon.framework.CascadingRuntimeException ;
+import org.apache.avalon.framework.configuration.Configuration ;
+import org.apache.avalon.cornerstone.services.threads.ThreadManager ;
+import org.apache.avalon.framework.configuration.ConfigurationException ;
+import javax.naming.ldap.LdapContext;
+
+
+/**
+ * ClientManager service implementation used to manage client sessions and
+ * their socket connections.
+ *
+ * @phoenix:block
+ * @phoenix:service name="org.apache.eve.client.ClientManager"
+ * @phoenix:mx-topic name="client-manager"
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.13 $
+ */
+public class ClientModule
+ extends AbstractStage
+ implements ClientManager
+{
+ public static final String SOCKETLISTENER_POOL = "client" ;
+
+ private Map m_sockets = new HashMap() ;
+ private Map m_sessions = new HashMap() ;
+ private Decoder m_decoder = null ;
+ private InputManager m_inputManager = null ;
+ private OutputManager m_outputManager = null ;
+ private UnifiedBackend m_nexus = null ;
+ private ProtocolEngine m_engine = null ;
+
+ /**
+ * We are using a ThreadLocal just as a means to key into a session based
+ * on the current thread of execution which has been associated with a
+ * session using the threadAssociate method. This is done to enable backend
+ * modules to access the session of the user performing operations without
+ * having to pass around the user session. The ThreadLocal actually maps
+ * the Thread to the ClientKey. <code>getClientSession()</code> without
+ * arguments simply accesses the ClientKey using the current executing
+ * Thread as the key into this ThreadLocal. The ClientKey is then used to
+ * return the ClientSession via another lookup into the m_sessions Map.
+ */
+ private ThreadLocal m_threadKeys = new ThreadLocal() ;
+
+ /**
+ * Thread outside of the protocol manager making calling nexus and backend
+ * methods through the JNDI provider need to propagate context environment
+ * parameters without passing is as an argument one each call. This Thread
+ * Local maps threads to JNDI contexts.
+ */
+ private ThreadLocal m_threadCtxs = new ThreadLocal() ;
+
+
+ // ---------------------------------------------------------
+ // Constructors
+ // ---------------------------------------------------------
+
+
+ /**
+ * Default constructor creates the client module by initializing a
+ * ConnectEventHandler for it.
+ */
+ public ClientModule()
+ {
+ m_handler = new ConnectEventHandler() ;
+ }
+
+
+ // ---------------------------------------------------------
+ // Stage Event Handler Class: ConnectionEventHandler
+ // ---------------------------------------------------------
+
+
+ /**
+ * The stage event handler for the ClientModule. This class processes
+ * incomming ConnectEvents thrown by the ServerListener service.
+ */
+ class ConnectEventHandler extends AbstractEventHandler
+ {
+ /**
+ * Primary event handling method to process a ConnectEvent.
+ *
+ * @param an_event must be a ConnectEvent subtype of EventObject
+ */
+ public void handleEvent( EventObject an_event )
+ {
+ Socket l_socket = null ;
+ Logger l_log = ClientModule.this.getLogger() ;
+ ClientKey l_clientKey = null ;
+ ConnectEvent l_event = null ;
+
+ try
+ {
+ if( an_event instanceof ConnectEvent )
+ {
+ l_event = ( ConnectEvent ) an_event ;
+ l_socket = ( Socket ) l_event.getSource() ;
+ l_clientKey = new ClientKey( l_socket ) ;
+ add( l_clientKey, l_socket ) ;
+ }
+ else
+ {
+ l_log.error( "Unknown event " + an_event + " ignored" ) ;
+ }
+ }
+ catch( Throwable t )
+ {
+ l_log.error( "Droping client " + l_clientKey
+ + " on handler error: ", t ) ;
+ drop( l_clientKey ) ;
+ }
+ }
+ }
+
+
+ // ---------------------------------------------------------
+ // Add/Drop/Get ClientSession Management Methods
+ // ---------------------------------------------------------
+
+
+ /**
+ * Drops a client connection and destroys the client's session associated
+ * with the calling thread.
+ */
+ public void drop()
+ {
+ drop( getClientKey() ) ;
+ }
+
+
+ /**
+ * Drops a client connection by unregistering the client with io managers
+ * and closing the client socket connection.
+ *
+ * @param a_clientKey the key of the client to drop
+ */
+ public void drop( ClientKey a_clientKey )
+ {
+ Socket l_socket = null ;
+ ClientSession l_session = null ;
+
+ // Unregister client key with io manager and expire it.
+ m_inputManager.unregister( a_clientKey ) ;
+ m_outputManager.unregister( a_clientKey ) ;
+ a_clientKey.expire() ;
+
+ // Remove client session from session map
+ synchronized( m_sessions )
+ {
+ l_session = ( ClientSession ) m_sessions.remove( a_clientKey ) ;
+ }
+
+ // Invalidate removed session to disable use by held handles to session
+ if( l_session != null )
+ {
+ l_session.invalidate() ;
+ }
+
+ // Remove client socket
+ synchronized( m_sockets )
+ {
+ l_socket = ( Socket ) m_sockets.remove( a_clientKey ) ;
+ }
+
+ // Close the client socket
+ if( null != l_socket )
+ {
+ try
+ {
+ l_socket.close() ;
+ }
+ catch( IOException e )
+ {
+ String l_msg = "Could not close client " + a_clientKey
+ + " socket!" ;
+ getLogger().error( l_msg, e ) ;
+ throw new ClientException( l_msg, e ) ;
+ }
+ }
+ }
+
+
+ /**
+ * Adds a client connection by registering the client io streams with the
+ * io managers and tracking the client using the supplied client key. The
+ * client's session is initialized using an anonymous principal. Later
+ * bind operations can change the session principal to represent the
+ * appropriate user.
+ *
+ * @param a_clientKey the key of the client to add.
+ * @param a_socket the client's socket.
+ */
+ public ClientSession add( ClientKey a_clientKey, Socket a_socket )
+ throws IOException
+ {
+ LdapClientSession l_session = null ;
+
+ // map client key to socket.
+ synchronized( m_sockets )
+ {
+ m_sockets.put( a_clientKey, a_socket ) ;
+ }
+
+ // Register Socket IO streams with the respective IO manager
+ m_inputManager.register( a_clientKey, a_socket.getInputStream() ) ;
+ m_outputManager.register( a_clientKey, a_socket.getOutputStream() ) ;
+
+ // Create a client session using the default principal (anonymous)
+ // which corresponds to an empty string for the distinguished name.
+ l_session = new LdapClientSession( a_clientKey, new LdapPrincipal() ) ;
+ m_sessions.put( a_clientKey, l_session ) ;
+ return l_session ;
+ }
+
+
+ /**
+ * Sets the user principal for a client on a bind operation. The protocol
+ * states that a bind operation requires the destruction of all outstanding
+ * operations. Hence all outstanding operations refered to by the client's
+ * key must be terminated, the session parameters are flushed, then the
+ * princal is set. The client affectively changes its role without dropping
+ * the socket connection.
+ *
+ * @todo need to make sure we stop all outstanding request operations before
+ * changing the principal of the user.
+ * @param a_clientKey the client's unique key.
+ * @param a_principal the new principal to be taken on by the client using
+ * the existing socket connection.
+ */
+ public ClientSession
+ setUserPrincipal( ClientKey a_clientKey, LdapPrincipal a_principal )
+ {
+ /** @todo */
+ // Must destroy existing operations here before changing the principal
+ LdapClientSession l_session = ( LdapClientSession )
+ m_sessions.get( a_clientKey ) ;
+
+ // We need to completely replace the session, expire the old key and
+ // create a new one and go from there rather than reseting the session
+ // we want old handles to be useless to both these objects and we
+ // want the code possessing it to be aware when it tries to use it.
+
+ // This is the only way to stop outstanding requests that are in stages
+ // other than those that are in the protocol engine stage. We basically
+ // need to destroy and recreate everything except the socket connection.
+
+ l_session.reset() ;
+ l_session.setPrincipal( a_principal ) ;
+ return l_session ;
+ }
+
+
+ /**
+ * Gets the ClientSession associated with the ClientKey argument.
+ *
+ * @param a_clientKey the unique client primary key
+ * @return the session of the client
+ */
+ public ClientSession getClientSession( ClientKey a_clientKey )
+ {
+ return ( ClientSession ) m_sessions.get( a_clientKey ) ;
+ }
+
+
+ /**
+ * Gets the key of the client on whose behalf the current thread is
+ * executing.
+ *
+ * @return the ClientKey associated with the callers thread or null if none
+ * exists.
+ */
+ public ClientKey getClientKey()
+ {
+ return ( ClientKey ) m_threadKeys.get() ;
+ }
+
+
+ /**
+ * Gets the ClientKey associated within the context of the calling Thread.
+ *
+ * @see threadAssociate()
+ * @see threadDisassociate()
+ * @return the session of the client associated with the calling Thread
+ */
+ public ClientSession getClientSession()
+ {
+ ClientKey l_key = ( ClientKey ) m_threadKeys.get() ;
+ return ( ClientSession ) m_sessions.get( l_key ) ;
+ }
+
+
+ /**
+ * Gets the LdapContext associated with the calling thread.
+ *
+ * @return the context of the caller thread
+ */
+ public LdapContext getLdapContext()
+ {
+ return ( LdapContext ) m_threadCtxs.get() ;
+ }
+
+
+ /**
+ * Associates the calling thread with a client using a ClientKey. A call to
+ * this method enables calls to getClientSession() without arguments to
+ * return a non-null ClientSession handle.
+ *
+ * @param a_clientKey the unique client primary key
+ */
+ public void threadAssociate( ClientKey a_clientKey )
+ {
+ m_threadKeys.set( a_clientKey ) ;
+ }
+
+
+ /**
+ * Associates the calling thread with a JNDI LdapContext. A call to
+ * this method enables calls to getLdapContext() without arguments to
+ * return an LdapContext handle.
+ *
+ * @param a_ctx the LdapContext to associate with the calling thread
+ */
+ public void threadAssociate( LdapContext a_ctx )
+ {
+ this.m_threadCtxs.set( a_ctx ) ;
+ }
+
+
+ /**
+ * Disassociates the calling thread with a client. After a call to this
+ * method the calling thread cannot acquire a non-null handle on a
+ * ClientSession object through a call to getClientSession() without
+ * arguments.
+ */
+ public void threadDisassociate()
+ {
+ if( m_threadKeys.get() != null )
+ {
+ m_threadKeys.set( null ) ;
+ }
+ else
+ {
+ m_threadCtxs.set( null ) ;
+ }
+ }
+
+
+ // ---------------------------------------------------------
+ // Listener Implementations
+ // ---------------------------------------------------------
+
+
+ /**
+ * ConnectListener interface implementation which asynchronously processes
+ * the ConnectEvent generated by the ServerListener service. It merely
+ * enqueues the event onto this Stage's event queue and returns immediately
+ * without processing the event in the thread of the caller.
+ *
+ * @param an_event a client connection event.
+ */
+ public void connectPerformed( ConnectEvent an_event )
+ throws CascadingRuntimeException
+ {
+ enqueue( an_event ) ;
+ }
+
+
+ // ---------------------------------------------------------
+ // Module & Life-Cycle Methods
+ // ---------------------------------------------------------
+
+
+ /**
+ * Overriden to enable handler after enabling this Module via a super
+ * method invokation.
+ *
+ * @param a_logger the logger to set this module and its handler to use
+ */
+ public void enableLogging( Logger a_logger )
+ {
+ super.enableLogging( a_logger ) ;
+ m_handler.enableLogging( a_logger ) ;
+ }
+
+
+ /**
+ * Gets the ROLE of the service this Module implements.
+ *
+ * @phoenix:mx-attribute
+ * @phoenix:mx-description gets the service interface (ROLE)
+ * @phoenix:mx-isWriteable no
+ * @return the role of this service.
+ */
+ public String getImplementationRole()
+ {
+ return ROLE ;
+ }
+
+
+ /**
+ * Gets a descriptive name for this module's implementation.
+ *
+ * @phoenix:mx-attribute
+ * @phoenix:mx-description gets the implementation name
+ * @phoenix:mx-isWriteable no
+ * @return descriptive implementation name.
+ */
+ public String getImplementationName()
+ {
+ return "Client Manager Module" ;
+ }
+
+
+ /**
+ * Gets the fully qualified class name of this service implementation class.
+ *
+ * @phoenix:mx-attribute
+ * @phoenix:mx-description gets the implementation class name
+ * @phoenix:mx-isWriteable no
+ * @return FQCN of this class.
+ */
+ public String getImplementationClassName()
+ {
+ return this.getClass().getName() ;
+ }
+
+
+ /**
+ * Gets a handle on various services minux the ThreadManager which is
+ * accessed by the service method of the AbstractStage superclass.
+ *
+ * @phoenix:dependency name="org.apache.eve.decoder.Decoder"
+ * @phoenix:dependency name="org.apache.eve.input.InputManager"
+ * @phoenix:dependency name="org.apache.eve.output.OutputManager"
+ * @phoenix:dependency name="org.apache.eve.backend.UnifiedBackend"
+ * @phoenix:dependency name="org.apache.eve.protocol.ProtocolEngine"
+ * @phoenix:dependency name="org.apache.avalon.cornerstone.services.threads.ThreadManager"
+ */
+ public void service( ServiceManager a_manager )
+ throws ServiceException
+ {
+ super.service( a_manager ) ;
+ m_decoder = ( Decoder ) a_manager.lookup( Decoder.ROLE ) ;
+ m_nexus = ( UnifiedBackend ) a_manager.lookup( UnifiedBackend.ROLE ) ;
+ m_engine = ( ProtocolEngine ) a_manager.lookup( ProtocolEngine.ROLE ) ;
+ m_inputManager = ( InputManager )
+ a_manager.lookup( InputManager.ROLE ) ;
+ m_outputManager = ( OutputManager )
+ a_manager.lookup( OutputManager.ROLE ) ;
+ }
+
+
+ /**
+ * Initializes this module by registering it with various slave modules like
+ * the InputManager, OutputManager and ProtocolEngine services.
+ */
+ public void initialize()
+ throws Exception
+ {
+ m_nexus.registerClientManager( this ) ;
+ m_engine.registerClientManager( this ) ;
+ m_inputManager.registerClientManager( this ) ;
+ m_outputManager.registerClientManager( this ) ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/client/ClientSession.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/client/ClientSession.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,62 @@
+/*
+ * $Id: ClientSession.java,v 1.4 2003/08/22 21:15:55 akarasulu Exp $
+ * $Prologue$
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.client ;
+
+
+import java.util.Locale ;
+import java.util.Iterator;
+
+import org.apache.eve.security.LdapPrincipal ;
+
+
+
+public interface ClientSession
+{
+ ClientKey getClientKey() ;
+
+ ////////////////////////////
+ // Session Attribute APIs //
+ ////////////////////////////
+
+ boolean isValid() ;
+
+ Iterator getAttributeNames() ;
+
+ Object getAttribute(String an_attrName) ;
+
+ void removeAttribute(String an_attrName) ;
+
+ void setAttribute(String an_attrName, Object a_attrValue) ;
+
+ void invalidate() ;
+
+ boolean isNew() ;
+
+ long getCreationTime() ;
+
+ long getLastAccessedTime() ;
+
+ int getMaxInactiveInterval() ;
+
+ void setMaxInactiveInterval(int an_interval) ;
+
+ //ServerConfig getServerConfig() ;
+
+
+ /////////////////////////
+ // Session Client APIs //
+ /////////////////////////
+
+
+ Locale getLocale() ;
+
+ LdapPrincipal getPrincipal() ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/client/KeyExpiryException.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/client/KeyExpiryException.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,28 @@
+/*
+ * $Id: KeyExpiryException.java,v 1.1 2003/03/22 19:55:29 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.client;
+
+/**
+ * Exception thrown when an accessor method is used on an expired ClientKey
+ */
+public class KeyExpiryException extends Exception {
+ /** Constructs an Exception without a message. */
+ public KeyExpiryException() {
+ super();
+ }
+
+ /**
+ * Constructs an Exception with a detailed message.
+ * @param Message The message associated with the exception.
+ */
+ public KeyExpiryException(String message) {
+ super(message);
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/client/LdapClientSession.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/client/LdapClientSession.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,156 @@
+/*
+ * $Id: LdapClientSession.java,v 1.2 2003/08/22 21:15:55 akarasulu Exp $
+ * $Prologue$
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.client ;
+
+
+import java.util.Locale ;
+import java.util.Iterator ;
+import java.util.Hashtable ;
+import java.util.Observable ;
+
+import org.apache.eve.security.LdapPrincipal ;
+
+
+public class LdapClientSession
+ extends Observable
+ implements ClientSession
+{
+ public static final int MAX_INACTIVE_INTERVAL = 900 ;
+
+ private final long m_creationTime = System.currentTimeMillis() ;
+ private final Hashtable m_attribs = new Hashtable() ;
+
+ protected boolean m_isNew = true ;
+ protected boolean m_isValid = true ;
+ protected int m_maxInactiveInterval = MAX_INACTIVE_INTERVAL ;
+ protected long m_lastAccessedTime = m_creationTime ;
+ protected final ClientKey m_clientKey ;
+ protected LdapPrincipal m_principal = null ;
+ protected ServerConfig m_serverConfig = null ;
+
+
+ public LdapClientSession(ClientKey a_clientKey, LdapPrincipal a_principal)
+ {
+ m_clientKey = a_clientKey ;
+ m_principal = a_principal ;
+ }
+
+
+ ////////////////////////////
+ // Session Attribute APIs //
+ ////////////////////////////
+
+
+ public Object getAttribute(String an_attrName)
+ {
+ return m_attribs.get(an_attrName) ;
+ }
+
+
+ public void removeAttribute(String an_attrName)
+ {
+ m_attribs.remove(an_attrName) ;
+ }
+
+
+ public void setAttribute(String an_attrName, Object a_attrValue)
+ {
+ m_attribs.put(an_attrName, a_attrValue) ;
+ }
+
+
+ public Iterator getAttributeNames()
+ {
+ return m_attribs.keySet().iterator() ;
+ }
+
+
+ public void invalidate()
+ {
+ m_isValid = false ;
+ m_attribs.clear() ;
+ super.setChanged() ;
+ }
+
+
+ public ClientKey getClientKey()
+ {
+ return m_clientKey ;
+ }
+
+
+ public boolean isNew()
+ {
+ return m_isNew ;
+ }
+
+
+ public long getCreationTime()
+ {
+ return m_creationTime ;
+ }
+
+
+ public long getLastAccessedTime()
+ {
+ return m_lastAccessedTime ;
+ }
+
+
+ public int getMaxInactiveInterval()
+ {
+ return m_maxInactiveInterval ;
+ }
+
+
+ public void setMaxInactiveInterval(int a_maxInactiveInterval)
+ {
+ m_maxInactiveInterval = a_maxInactiveInterval ;
+ }
+
+
+ /////////////////////////
+ // Session Client APIs //
+ /////////////////////////
+
+
+ public Locale getLocale()
+ {
+ return m_principal.getLocale() ;
+ }
+
+
+ public LdapPrincipal getPrincipal()
+ {
+ return m_principal ;
+ }
+
+
+ public void setPrincipal(LdapPrincipal a_principal)
+ {
+ m_principal = a_principal ;
+ }
+
+
+ public boolean isValid()
+ {
+ return m_isValid ;
+ }
+
+
+ void reset() {
+ m_attribs.clear() ;
+ m_isNew = true ;
+ m_isValid = true ;
+ m_maxInactiveInterval = MAX_INACTIVE_INTERVAL ;
+ m_lastAccessedTime = System.currentTimeMillis() ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/client/ServerConfig.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/client/ServerConfig.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,22 @@
+/*
+ * $Id: ServerConfig.java,v 1.2 2003/03/13 18:27:08 akarasulu Exp $
+ * $Prologue$
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+package org.apache.eve.client ;
+
+
+
+import java.util.Iterator ;
+
+
+public interface ServerConfig
+{
+ String getServerName() ;
+ String getInitParameter(String a_paramName) ;
+ Iterator getInitParameterNames() ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/decoder/Decoder.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/decoder/Decoder.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,29 @@
+/*
+ * $Id: Decoder.java,v 1.4 2003/03/26 02:09:15 jmachols Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.decoder ;
+
+
+import org.apache.eve.event.InputListener ;
+
+
+/**
+ * Service interface for decoding an ASN.1 BER encoded stream to demarshal
+ * LDAP protocol request messages.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: jmachols $
+ * @version $Revision: 1.4 $
+ */
+public interface Decoder
+ extends InputListener
+{
+ /** Role played by the service as defined in Avalon */
+ String ROLE = Decoder.class.getName() ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/decoder/DecoderException.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/decoder/DecoderException.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,38 @@
+/*
+ * $Id: DecoderException.java,v 1.2 2003/03/13 18:27:09 akarasulu Exp $
+ * $Prologue$
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.decoder ;
+
+
+import org.apache.avalon.framework.CascadingRuntimeException ;
+
+
+/** This exception is thrown when protocol errors occurred */
+public class DecoderException extends CascadingRuntimeException
+{
+ /**
+ * Constructs an Exception with a detailed message.
+ * @param Message The message associated with the exception.
+ */
+ public DecoderException(String message, Throwable t)
+ {
+ super(message, t) ;
+ }
+
+
+ /**
+ * Constructs an Exception with a detailed message.
+ * @param Message The message associated with the exception.
+ */
+ public DecoderException(String message)
+ {
+ super(message, null) ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/decoder/DecoderModule.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/decoder/DecoderModule.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,246 @@
+/*
+ * $Id: DecoderModule.java,v 1.8 2003/08/22 21:15:55 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.decoder ;
+
+
+import java.io.InputStream ;
+import java.util.EventObject ;
+
+import org.apache.ldap.common.message.Request ;
+import org.apache.ldap.common.message.MessageDecoder ;
+
+import org.apache.eve.event.InputEvent ;
+import org.apache.eve.client.ClientKey ;
+import org.apache.eve.event.RequestEvent ;
+import org.apache.eve.seda.AbstractStage ;
+import org.apache.eve.client.KeyExpiryException ;
+import org.apache.eve.protocol.ProtocolEngine ;
+import org.apache.eve.event.AbstractEventHandler ;
+
+import org.apache.avalon.framework.logger.Logger ;
+import org.apache.avalon.framework.service.ServiceManager ;
+import org.apache.avalon.framework.service.ServiceException ;
+
+
+/**
+ * Decoder service implemented as a stage for ASN.1 Binary encoded LDAPv3 data.
+ *
+ * @phoenix:block
+ * @phoenix:mx-topic name="DecoderModule"
+ * @phoenix:service name="org.apache.eve.decoder.Decoder"
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.8 $
+ */
+public class DecoderModule
+ extends AbstractStage
+ implements Decoder
+{
+ /** Handle on the ldap request protocol processing engine */
+ private ProtocolEngine m_engine = null ;
+
+ /** MessageDecoder used to decode messages in a provider independent way. */
+ private MessageDecoder m_msgDecoder = null ;
+
+
+ // ------------------------------------------------------------------------
+ // Default Constructor
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Creates an instance of the Decoder service module. Initializes the
+ * stage's event handler so the next life-cycle method can enable logging.
+ *
+ * @todo look into the correct way to enable logging in these handlers while
+ * making their instantiation reside within the initialize life-cycle
+ * method.
+ */
+ public DecoderModule()
+ {
+ m_handler = new InputEventHandler() ;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // InputListener Interface Method Implementations
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * InputListener interface method implementation enabling this DecoderModule
+ * to detect the reception of InputEvents. Simply enqueues the event onto
+ * this Stage's event queue returning immediately thereafter. The event is
+ * processed by this Stage's event handler.
+ *
+ * @param a_event InputEvent encapsulating the ClientKey and the client
+ * Socket's InputStream.
+ */
+ public void inputReceived( InputEvent a_event )
+ {
+ enqueue( a_event ) ;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // Module Interface Method Implementations
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Gets this Module implementation's service interface (a.k.a its role)
+ *
+ * @return the service interface name
+ * @phoenix:mx-attribute
+ * @phoenix:mx-description gets the service interface (ROLE)
+ * @phoenix:mx-isWriteable no
+ */
+ public String getImplementationRole()
+ {
+ return ROLE ;
+ }
+
+
+ /**
+ * Gets this Module implementation's descriptive name.
+ *
+ * @return descriptive module name
+ * @phoenix:mx-attribute
+ * @phoenix:mx-description gets the descriptive name
+ * @phoenix:mx-isWriteable no
+ */
+ public String getImplementationName()
+ {
+ return "ASN.1 LDAPv3 BER Decoder Module" ;
+ }
+
+
+ /**
+ * Gets this Module implementation's fully qualified class name.
+ *
+ * @return the fqcn
+ * @phoenix:mx-attribute
+ * @phoenix:mx-description gets the FQCN
+ * @phoenix:mx-isWriteable no
+ */
+ public String getImplementationClassName()
+ {
+ return this.getClass().getName() ;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // Avalon Life-Cycle Interface Method Implementations
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Method override to make sure that the handler's logger is initialized
+ * after calling the super method.
+ *
+ * @param a_logger the Logger for this module.
+ */
+ public void enableLogging( Logger a_logger )
+ {
+ super.enableLogging( a_logger ) ;
+ m_handler.enableLogging( a_logger ) ;
+ }
+
+
+ /**
+ * Initialization instantiates the MessageDecoder.
+ *
+ * @todo see if there is any value in adding an optional configuration
+ * parameter to switch the BER library provider based on a configuration
+ * property for this module.
+ */
+ public void initialize() throws Exception
+ {
+ m_msgDecoder = new MessageDecoder() ;
+ }
+
+
+ /**
+ * Grabs handle directly on ProtocolEngine yet super call grabs the
+ * ThreadManager.
+ *
+ * @phoenix:dependency name="org.apache.eve.protocol.ProtocolEngine"
+ * @phoenix:dependency name="org.apache.avalon.cornerstone.services.threads.ThreadManager"
+ */
+ public void service( ServiceManager a_manager )
+ throws ServiceException
+ {
+ super.service( a_manager ) ;
+ m_engine = ( ProtocolEngine ) a_manager.lookup( ProtocolEngine.ROLE ) ;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // Decoder EventHandler Implementation Class
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Decoder stage EventHandler implementation whose handleEvent method is the
+ * primary work function driven by this stage's worker threads.
+ */
+ class InputEventHandler extends AbstractEventHandler
+ {
+ /**
+ * Handles an InputEvent by decoding the binary encoded byte stream
+ * contained within a_event parameter in a BER Library provider
+ * independant fashion.
+ *
+ * @param a_event the InputEvent as an EventObject.
+ */
+ public void handleEvent( EventObject a_event )
+ {
+ Object l_lock = null ;
+ InputStream l_in = null ;
+ InputEvent l_event = null ;
+ ClientKey l_clientKey = null ;
+
+ // Check first event type is correct
+ if( ! ( a_event instanceof InputEvent ) )
+ {
+ throw new DecoderException( "Unrecognized event: " + a_event ) ;
+ }
+
+ // Extract event info and init local vars
+ l_event = ( InputEvent ) a_event ;
+ l_clientKey = ( ClientKey ) l_event.getSource() ;
+ l_in = l_event.getInputStream() ;
+
+ // Obtain input lock object or return.
+ try
+ {
+ l_lock = l_clientKey.getInputLock() ;
+ }
+ catch( KeyExpiryException e )
+ {
+ if( getLogger().isWarnEnabled() )
+ {
+ getLogger().warn( "ClientKey for " + l_clientKey
+ + " has expired right after server accept: ", e ) ;
+ }
+
+ return ;
+ }
+
+ // Decode the request, build the event and deliver to the engine
+ Request l_request = ( Request )
+ m_msgDecoder.decode( l_lock, l_in ) ;
+ RequestEvent l_requestEvent =
+ new RequestEvent( l_clientKey, l_request ) ;
+ m_engine.requestReceived( l_requestEvent ) ;
+ }
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/encoder/Encoder.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/encoder/Encoder.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,41 @@
+/*
+ * $Id: Encoder.java,v 1.4 2003/08/22 21:15:55 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.encoder ;
+
+
+import org.apache.ldap.common.message.Response ;
+
+import org.apache.eve.event.ResponseListener ;
+
+
+/**
+ * Avalon service interface for a module that encodes a Response using Basic
+ * Encoding Rules into an LDAPv3 Protocol Data Unit (PDU) that can be delivered
+ * over the wire.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.4 $
+ */
+public interface Encoder
+ extends ResponseListener
+{
+ String ROLE = Encoder.class.getName() ;
+
+ /**
+ * Synchronously encodes an LDAPv3 protocol Response message into a byte
+ * buffer that can be written to a Stream as an BER encoded PDU.
+ *
+ * @param a_response the LDAP Response message to be encoded.
+ */
+ public byte [] encode( Response a_response )
+ throws EncoderException ;
+}
+
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/encoder/EncoderException.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/encoder/EncoderException.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,38 @@
+/*
+ * $Id: EncoderException.java,v 1.2 2003/03/13 18:27:12 akarasulu Exp $
+ * $Prologue$
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.encoder ;
+
+
+import org.apache.avalon.framework.CascadingRuntimeException ;
+
+
+/** This exception is thrown when protocol errors occurred */
+public class EncoderException extends CascadingRuntimeException
+{
+ /**
+ * Constructs an Exception with a detailed message.
+ * @param Message The message associated with the exception.
+ */
+ public EncoderException(String message, Throwable t)
+ {
+ super(message, t) ;
+ }
+
+
+ /**
+ * Constructs an Exception with a detailed message.
+ * @param Message The message associated with the exception.
+ */
+ public EncoderException(String message)
+ {
+ super(message, null) ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/encoder/EncoderModule.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/encoder/EncoderModule.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,283 @@
+/*
+ * $Id: EncoderModule.java,v 1.6 2003/08/22 21:15:55 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.encoder ;
+
+
+import java.util.EventObject ;
+import java.io.ByteArrayInputStream ;
+
+import org.apache.avalon.framework.logger.Logger ;
+import org.apache.avalon.framework.service.ServiceManager ;
+import org.apache.avalon.framework.service.ServiceException ;
+import org.apache.avalon.framework.CascadingRuntimeException ;
+
+import org.apache.ldap.common.message.Response ;
+import org.apache.ldap.common.message.MessageEncoder ;
+import org.apache.ldap.common.message.MessageException ;
+
+import org.apache.eve.client.ClientKey ;
+import org.apache.eve.event.OutputEvent ;
+import org.apache.eve.seda.AbstractStage ;
+import org.apache.eve.event.ResponseEvent ;
+import org.apache.eve.output.OutputManager ;
+import org.apache.eve.event.AbstractEventHandler ;
+
+
+/**
+ * Encodes Protocol Data Unit (PDU) using Basic Encoding (BER) Rules.
+ *
+ * @phoenix:block
+ * @phoenix:service name="org.apache.eve.encoder.Encoder"
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.6 $
+ */
+public class EncoderModule
+ extends AbstractStage
+ implements Encoder
+{
+ /** Handle on the output manager which recieves events from this module. */
+ private OutputManager m_outputManager = null ;
+
+ /** Encoding machinery from the message/BERlib provider framework. */
+ private MessageEncoder m_msgEncoder = null ;
+
+
+ // ------------------------------------------------------------------------
+ // Default Constructor
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Constructor initializes this stage's event handler by instantiating a
+ * ResponseEventHandler which is a named inner class. The event handler is
+ * used to process events after they are dequeued off of the stage's event
+ * queue. The handler's handleEvent is called with an EventObject by stage
+ * worker threads which drive event handling. Pesently this is instantiated
+ * here because rather than within the initialize method because the handler
+ * is LogEnabled when the EncoderModule is in the enableLogging life-cycle
+ * method.
+ *
+ * @todo look into the correct way to enable logging in these handlers while
+ * making their instantiation reside within the initialize life-cycle
+ * method.
+ */
+ public EncoderModule()
+ {
+ m_handler = new ResponseEventHandler() ;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // Encoder Service Interface Method Implementations
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Synchronously encodes an LDAPv3 protocol Response message into a byte
+ * buffer that can be written to a Stream as an BER encoded PDU.
+ *
+ * @param a_response the LDAP Response message to be encoded.
+ */
+ public byte [] encode( Response a_response )
+ throws EncoderException
+ {
+ byte [] l_buf = null ;
+
+ try
+ {
+ l_buf = m_msgEncoder.encode( a_response ) ;
+ }
+ catch( MessageException me )
+ {
+ getLogger().error( "Encoder error: ", me ) ;
+ throw new EncoderException( "Encoder error: ", me ) ;
+ }
+
+ return l_buf ;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // ResponseListener Interface Method Implementations
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Listener's handler method simply enqueues the ResponseEvent on this
+ * stage's event queue for asynchronous processing by stage worker threads.
+ *
+ * @param a_event the ResponseEvent to handle.
+ */
+ public void responseComposed( ResponseEvent a_event )
+ throws CascadingRuntimeException
+ {
+ enqueue( a_event ) ;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // Module Interface Method Implementations
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Gets the service interface name of this module.
+ *
+ * @return the role of this module's implemented service.
+ * @phoenix:mx-attribute
+ * @phoenix:mx-description Returns the service role name.
+ * @phoenix:mx-isWriteable no
+ */
+ public String getImplementationRole()
+ {
+ return ROLE ;
+ }
+
+
+ /**
+ * Gets the name of the implementation. For example the name of the
+ * Berkeley DB Backend module is "Berkeley DB Backend".
+ *
+ * @return String representing the module implementation type name.
+ * @phoenix:mx-attribute
+ * @phoenix:mx-description Returns the implementation name.
+ * @phoenix:mx-isWriteable no
+ */
+ public String getImplementationName()
+ {
+ return "ASN.1 BER Encoder Module" ;
+ }
+
+
+ /**
+ * Gets the name of the implementation class. For example the name of the
+ * Berkeley DB Backend implementation class is <code>
+ * "ldapdd.backend.berkeley.BackendBDb" </code>.
+ *
+ * @return String representing the module implementation's class name.
+ * @phoenix:mx-attribute
+ * @phoenix:mx-description Returns the implementation class name.
+ * @phoenix:mx-isWriteable no
+ */
+ public String getImplementationClassName()
+ {
+ return this.getClass().getName() ;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // Avalon Framework Life-Cycle Methods
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Log enables the handler right after calling the super method.
+ *
+ * @param a_logger the logger used by this module.
+ */
+ public void enableLogging( Logger a_logger )
+ {
+ super.enableLogging( a_logger ) ;
+ m_handler.enableLogging( a_logger ) ;
+ }
+
+
+ /**
+ * Initialization instantiates the MessageEncoder.
+ *
+ * @todo see if there is any value in adding an optional configuration
+ * parameter to switch the BER library provider based on a configuration
+ * property for this module.
+ */
+ public void initialize() throws Exception
+ {
+ m_msgEncoder = new MessageEncoder() ;
+ }
+
+
+ /**
+ * Service method grabs a handle on the OutputManager directly and its
+ * super method implementation grabs a handler on the cornerstone
+ * ThreadManager for getting the stage's thread pool.
+ *
+ * @phoenix:dependency name="org.apache.eve.output.OutputManager"
+ * @phoenix:dependency name="org.apache.avalon.cornerstone.services.threads.ThreadManager"
+ */
+ public void service( ServiceManager a_manager )
+ throws ServiceException
+ {
+ super.service( a_manager ) ;
+ m_outputManager = ( OutputManager )
+ a_manager.lookup( OutputManager.ROLE ) ;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // Stage EventHandler Class Definition
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Stage event handler class definition.
+ */
+ class ResponseEventHandler extends AbstractEventHandler
+ {
+ /**
+ * Check and cast a response event. Then processes event by encoding
+ * the response into a byte [] buffer using the parent class' encode
+ * method. Builds the OutputEvent and delivers it to the OutputManager.
+ *
+ * @param an_event the ResponseEvent to process.
+ */
+ public void handleEvent( EventObject an_event )
+ {
+ if( ! ( an_event instanceof ResponseEvent ) )
+ {
+ throw new EncoderException( "Unrecognized event: "
+ + an_event ) ;
+ }
+
+ ResponseEvent l_event = ( ResponseEvent ) an_event ;
+
+ try {
+ if( ! ( an_event instanceof ResponseEvent ) )
+ {
+ throw new EncoderException("Unrecognized event: " +
+ l_event) ;
+ }
+
+ ClientKey l_client = ( ClientKey ) an_event.getSource() ;
+ byte [] l_buf = encode( l_event.getResponse() ) ;
+ ByteArrayInputStream l_in = new ByteArrayInputStream( l_buf ) ;
+
+ if( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug( "Response encoded for client "
+ + l_client ) ;
+ getLogger().debug( "About to hand off response to client "
+ + "manager within encoder event") ;
+ }
+
+ OutputEvent l_outEvent = new OutputEvent( l_client, l_in ) ;
+ m_outputManager.writeResponse( l_outEvent ) ;
+
+ if( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug( "Handed off OutputEvent for client "
+ + l_client + " to OutputManager" ) ;
+ }
+ } catch(Throwable t) {
+ getLogger().error( "Encoder Stage Handler: ", t ) ;
+ }
+ }
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/event/AbstractEventHandler.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/event/AbstractEventHandler.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,19 @@
+/*
+ * $Id: AbstractEventHandler.java,v 1.2 2003/03/13 18:27:14 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.event ;
+
+import org.apache.avalon.framework.logger.AbstractLogEnabled ;
+
+public abstract class AbstractEventHandler
+ extends AbstractLogEnabled
+ implements EventHandler
+{
+}
+
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/event/AuthenticationEvent.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/event/AuthenticationEvent.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,36 @@
+/*
+ * $Id: AuthenticationEvent.java,v 1.2 2003/03/13 18:27:14 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.event ;
+
+
+import java.util.EventObject ;
+
+import org.apache.eve.client.ClientKey ;
+import java.security.Principal ;
+
+
+public class AuthenticationEvent
+ extends EventObject
+{
+ final Principal m_principal ;
+
+
+ public AuthenticationEvent(ClientKey a_client, Principal a_principal)
+ {
+ super(a_client) ;
+ m_principal = a_principal ;
+ }
+
+
+ public Principal getPrincipal()
+ {
+ return m_principal ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/event/AuthenticationListener.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/event/AuthenticationListener.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,15 @@
+/*
+ * $Id: AuthenticationListener.java,v 1.2 2003/03/13 18:27:15 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.event;
+
+public interface AuthenticationListener
+{
+}
+
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/event/ClientEvent.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/event/ClientEvent.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,49 @@
+/*
+ * $Id: ClientEvent.java,v 1.2 2003/03/13 18:27:16 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.event ;
+
+
+import java.net.Socket ;
+import java.util.EventObject ;
+import org.apache.eve.client.ClientKey ;
+
+
+public class ClientEvent
+ extends EventObject
+{
+ public final static int DROP_EVENT = 0 ;
+ public final static int ADD_EVENT = 1 ;
+ public final static int OUTPUT_EVENT = 2 ;
+ public final static int INPUT_EVENT = 3 ;
+ public final static int REQUEST_EVENT = 4 ;
+ public final static int RESPONSE_EVENT = 5 ;
+ public final static int AUTH_EVENT = 6 ;
+
+ public final int type ;
+
+
+ public ClientEvent(ClientKey a_client, int a_type)
+ {
+ super(a_client) ;
+ type = a_type ;
+ }
+
+
+ public ClientKey getClientKey()
+ {
+ return (ClientKey) this.source ;
+ }
+
+
+ public int getType()
+ {
+ return type ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/event/ClientListener.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/event/ClientListener.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,16 @@
+/*
+ * $Id: ClientListener.java,v 1.2 2003/03/13 18:27:17 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.event ;
+
+public interface ClientListener
+{
+ void clientAdded(ClientEvent a_client) ;
+ void clientDropped(ClientEvent a_client) ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/event/ConnectEvent.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/event/ConnectEvent.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,24 @@
+/*
+ * $Id: ConnectEvent.java,v 1.2 2003/03/13 18:27:17 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.event ;
+
+
+import java.net.Socket ;
+import java.util.EventObject;
+
+
+public class ConnectEvent
+ extends EventObject
+{
+ public ConnectEvent(Socket a_socket)
+ {
+ super(a_socket) ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/event/ConnectListener.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/event/ConnectListener.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,21 @@
+/*
+ * $Id: ConnectListener.java,v 1.3 2003/03/13 18:27:18 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.event ;
+
+
+import java.util.EventListener ;
+
+
+public interface ConnectListener
+ extends EventListener
+{
+ void connectPerformed(ConnectEvent an_event) ;
+}
+
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/event/EntryEvent.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/event/EntryEvent.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,23 @@
+/*
+ * $Id: EntryEvent.java,v 1.2 2003/03/13 18:27:19 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.event ;
+
+
+import java.util.EventObject ;
+
+
+public class EntryEvent
+ extends EventObject
+{
+ public EntryEvent(Object a_source)
+ {
+ super(a_source) ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/event/EntryEventSource.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/event/EntryEventSource.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,17 @@
+/*
+ * $Id: EntryEventSource.java,v 1.2 2003/03/13 18:27:19 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.event ;
+
+public interface EntryEventSource
+{
+ void addEntryListener(EntryListener a_listener) ;
+ void removeEntryListener(EntryListener a_listener) ;
+}
+
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/event/EntryListener.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/event/EntryListener.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,21 @@
+/*
+ * $Id: EntryListener.java,v 1.2 2003/03/13 18:27:20 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.event ;
+
+import java.util.EventListener ;
+
+public interface EntryListener
+ extends EventListener
+{
+ void entryAdded(EntryEvent an_event) ;
+ void entryChanged(EntryEvent an_event) ;
+ void entryRemoved(EntryEvent an_event) ;
+}
+
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/event/EventHandler.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/event/EventHandler.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,42 @@
+/*
+ * $Id: EventHandler.java,v 1.3 2003/08/22 21:15:55 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.event ;
+
+
+import java.util.EventObject ;
+import java.util.EventListener ;
+
+import org.apache.avalon.framework.logger.LogEnabled ;
+import org.apache.avalon.framework.service.Serviceable ;
+import org.apache.avalon.framework.context.Contextualizable ;
+import org.apache.avalon.framework.CascadingRuntimeException ;
+
+
+/**
+ * Event handler used by Stages.
+ *
+ * @todo Should this even be LogEnabled? Not a good idea I think. Let's think
+ * about refactoring this later down the road.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.3 $
+ */
+public interface EventHandler
+ extends EventListener, LogEnabled
+{
+ /**
+ * Exception is explicitly made to be a runtime exception so it can tunnel
+ * up through the run() call of handler Runnable.
+ *
+ * @param a_event the event to process or handle.
+ */
+ void handleEvent( EventObject a_event ) ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/event/InputEvent.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/event/InputEvent.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,35 @@
+/*
+ * $Id: InputEvent.java,v 1.2 2003/03/13 18:27:20 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.event ;
+
+import java.util.EventObject ;
+import java.io.InputStream ;
+import org.apache.eve.client.ClientKey;
+
+
+public class InputEvent
+ extends EventObject
+{
+ private final InputStream m_in ;
+
+
+ public InputEvent(ClientKey a_client, InputStream a_in)
+ {
+ super(a_client) ;
+ m_in = a_in ;
+ }
+
+
+ public InputStream getInputStream()
+ {
+ return m_in ;
+ }
+}
+
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/event/InputListener.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/event/InputListener.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,19 @@
+/*
+ * $Id: InputListener.java,v 1.2 2003/03/13 18:27:21 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.event ;
+import org.apache.avalon.framework.CascadingException;
+import java.util.EventListener;
+
+
+public interface InputListener
+ extends EventListener
+{
+ void inputReceived(InputEvent an_event) ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/event/OutputEvent.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/event/OutputEvent.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,33 @@
+/*
+ * $Id: OutputEvent.java,v 1.2 2003/03/13 18:27:21 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.event ;
+
+import java.io.InputStream ;
+import java.util.EventObject;
+import org.apache.eve.client.ClientKey;
+
+
+public class OutputEvent
+ extends ClientEvent
+{
+ private final InputStream m_in ;
+
+ public OutputEvent(final ClientKey a_client, final InputStream a_dataStream)
+ {
+ super(a_client, OUTPUT_EVENT) ;
+ m_in = a_dataStream ;
+ }
+
+
+ public InputStream getInputStream()
+ {
+ return m_in ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/event/OutputListener.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/event/OutputListener.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,21 @@
+/*
+ * $Id: OutputListener.java,v 1.2 2003/03/13 18:27:22 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.event ;
+
+
+import org.apache.avalon.framework.CascadingRuntimeException ;
+import java.util.EventListener;
+
+
+public interface OutputListener
+ extends EventListener
+{
+ void writeResponse(OutputEvent an_event) ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/event/RequestEvent.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/event/RequestEvent.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,56 @@
+/*
+ * $Id: RequestEvent.java,v 1.3 2003/08/22 21:15:55 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.event ;
+
+
+import java.util.EventObject ;
+
+import org.apache.ldap.common.message.Request ;
+import org.apache.eve.client.ClientKey ;
+
+
+/**
+ * Event which announces the arrival of a LDAPv3 client request.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.3 $
+ */
+public class RequestEvent
+ extends EventObject
+{
+ /** The decoded request associated with this event. */
+ private final Request m_request ;
+
+
+ /**
+ * Creates an event wrapper around a client key and a request for that
+ * client.
+ *
+ * @param a_clientKey the unique key identifying a client.
+ * @param a_request the request object associated with this event.
+ */
+ public RequestEvent( final ClientKey a_clientKey, final Request a_request )
+ {
+ super( a_clientKey ) ;
+ m_request = a_request ;
+ }
+
+
+ /**
+ * Gets the client request associated with this event.
+ *
+ * @return the client Request.
+ */
+ public Request getRequest()
+ {
+ return m_request ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/event/RequestListener.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/event/RequestListener.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,30 @@
+/*
+ * $Id: RequestListener.java,v 1.3 2003/03/13 18:27:24 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.event ;
+
+
+import java.util.EventListener ;
+import org.apache.avalon.framework.CascadingException ;
+
+
+/**
+ * Generic interface extended by the ProtocolEngine service interface to enable
+ * the receipt of RequestEvents encapsulating a client's request PDU.
+ */
+public interface RequestListener
+ extends EventListener
+{
+ /**
+ * RequestEvent handler of the listener.
+ *
+ * @param an_event a RequestEvent encapsulating the client's request PDU.
+ */
+ void requestReceived(RequestEvent an_event) ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/event/ResponseEvent.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/event/ResponseEvent.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,56 @@
+/*
+ * $Id: ResponseEvent.java,v 1.3 2003/08/22 21:15:55 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.event ;
+
+
+import java.util.EventObject ;
+
+import org.apache.eve.client.ClientKey ;
+import org.apache.ldap.common.message.Response ;
+
+
+/**
+ * An event representing the composition of a response to a client request.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.3 $
+ */
+public class ResponseEvent
+ extends EventObject
+{
+ /** The Reponse composed for a client request. */
+ private final Response m_response ;
+
+
+ /**
+ * Creates a ResponseEvent for a client identified by a key on a response.
+ *
+ * @param a_clientKey a unique client identifying key.
+ * @param a_response the response this event announces the composition of.
+ */
+ public ResponseEvent( final ClientKey a_clientKey,
+ final Response a_response )
+ {
+ super( a_clientKey ) ;
+ m_response = a_response ;
+ }
+
+
+ /**
+ * Gets the response object associated with this event.
+ *
+ * @return the LDAPv3 Response message.
+ */
+ public Response getResponse()
+ {
+ return m_response ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/event/ResponseListener.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/event/ResponseListener.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,35 @@
+/*
+ * $Id: ResponseListener.java,v 1.4 2003/08/22 21:15:55 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.event ;
+
+
+import java.util.EventListener ;
+
+import org.apache.avalon.framework.CascadingRuntimeException ;
+
+
+/**
+ * Components which listen for the composition of a response.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.4 $
+ */
+public interface ResponseListener
+ extends EventListener
+{
+ /**
+ * Listener's handler method to take action upon the reciept of a
+ * ResponseEvent.
+ *
+ * @param a_event the ResponseEvent to handle.
+ */
+ void responseComposed( ResponseEvent a_event ) ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/AbandonEvent.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/AbandonEvent.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,26 @@
+/*
+ * $Id: AbandonEvent.java,v 1.2 2003/03/13 18:27:25 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.event.protocol ;
+
+
+import java.util.EventObject ;
+
+
+/**
+ * Event which logically represents a protocol abandon operation.
+ */
+public class AbandonEvent
+ extends ProtocolEvent
+{
+ public AbandonEvent(Object a_src, boolean a_isPduDelivered)
+ {
+ super(a_src, ABANDONREQUEST_MASK, a_isPduDelivered) ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/AddEvent.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/AddEvent.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,72 @@
+/*
+ * $Id: AddEvent.java,v 1.4 2003/04/09 15:51:27 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.event.protocol ;
+
+
+import javax.naming.directory.Attributes ;
+import javax.naming.Name;
+import javax.naming.directory.DirContext;
+
+
+/**
+ * Event which logically represents a protocol add operation. Changes to the
+ * set of attributes for the added entry in pre-event firing will effect the
+ * result. Meaning extra attributes and values or their deletion will be
+ * reflected in the added entry.
+ */
+public class AddEvent
+ extends ProtocolEvent
+{
+ private Name m_name ;
+ private Attributes m_attributes ;
+ private DirContext m_base ;
+
+
+ public AddEvent(Object a_src, boolean a_isPduDelivered)
+ {
+ super(a_src, ADDREQUEST_MASK, a_isPduDelivered) ;
+ }
+
+
+ public DirContext getBase()
+ {
+ return m_base ;
+ }
+
+
+ public void setBase(DirContext a_base)
+ {
+ m_base = a_base ;
+ }
+
+
+ public Name getName()
+ {
+ return m_name ;
+ }
+
+
+ public void setName(Name a_name)
+ {
+ m_name = a_name ;
+ }
+
+
+ public Attributes getAttributes()
+ {
+ return m_attributes ;
+ }
+
+
+ public void setAttributes(Attributes a_attribute)
+ {
+ m_attributes = a_attribute ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/BindEvent.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/BindEvent.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,164 @@
+/*
+ * $Id: BindEvent.java,v 1.3 2003/03/13 18:27:25 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.event.protocol ;
+
+
+import javax.naming.Name ;
+import java.security.Principal;
+
+
+/**
+ * Event which logically represents a protocol bind operation. Some properties
+ * of this event will only be present after the bind operation has completed.
+ * Changes to already initialized mutable event properties are not possible
+ * after.
+ */
+public class BindEvent
+ extends ProtocolEvent
+{
+ private Name m_dn ;
+ private Boolean isSimple = null ;
+ private Principal m_principal = null ;
+
+
+ /**
+ * Minimally creates a BindEvent without populating it with the information
+ * required to fire the event.
+ */
+ public BindEvent(Object a_src, boolean a_isPduDelivered)
+ {
+ super(a_src, BINDREQUEST_MASK, a_isPduDelivered) ;
+ }
+
+
+ /**
+ * Gets the unnormalized distinguished name of the user trying to bind.
+ * This parameter is available on both before and after event firings.
+ *
+ * @return the unnormalized distinguished name of the user
+ */
+ public Name getName()
+ {
+ if(null == m_dn) {
+ throw new IllegalStateException("BindEvent has not been properly "
+ + "initialized!") ;
+ }
+
+ return m_dn ;
+ }
+
+
+ /**
+ * Sets the unnormalized distinguished name of the user trying to bind.
+ * This parameter is available on both before and after event firings.
+ *
+ * @param a_dn the unnormalized distinguished name of the user
+ */
+ public void setName(Name a_dn)
+ {
+ if(null == m_dn) {
+ m_dn = a_dn ;
+ } else {
+ throw new IllegalStateException("Name change via setName() "
+ + "after propertiy initialization not allowed. setName() can "
+ + "be called at most once.") ;
+ }
+ }
+
+
+ /**
+ * Checks to see if the authentication method is simple. This event
+ * property is available on both before and after event firings.
+ *
+ * @return true if the authentication method is simple, false if it is SASL
+ */
+ public boolean isSimple()
+ {
+ if(null == isSimple) {
+ throw new IllegalStateException("BindEvent has not been properly "
+ + "initialized!") ;
+ }
+
+ return isSimple.booleanValue() ;
+ }
+
+
+ /**
+ * Checks to see if the authentication method is simple. This event
+ * property is available on both before and after event firings.
+ *
+ * @return true if the authentication method is simple, false if it is SASL
+ */
+ public boolean getSimple()
+ {
+ if(null == isSimple) {
+ throw new IllegalStateException("BindEvent has not been properly "
+ + "initialized!") ;
+ }
+
+ return isSimple.booleanValue() ;
+ }
+
+
+ /**
+ * Checks to see if the authentication method is simple. This event
+ * property is available on both before and after event firings.
+ *
+ * @param isSimple true if the authentication method is simple, false if it
+ * is SASL
+ */
+ public void setSimple(boolean isSimple)
+ {
+ if(null == this.isSimple) {
+ this.isSimple = new Boolean(isSimple) ;
+ } else {
+ throw new IllegalStateException("Name change via setSimple() "
+ + "after propertiy initialization not allowed. setName() can "
+ + "be called at most once.") ;
+ }
+ }
+
+
+ /**
+ * Gets the user principal that has just bound a session with the server.
+ * This event property is only available after the bind operation and can
+ * only be set once.
+ *
+ * @return the authenticated user.
+ */
+ public Principal getPrincipal()
+ {
+ if(null == m_principal) {
+ throw new IllegalStateException("BindEvent has not been properly "
+ + "initialized!\nThis will be the case if this property is "
+ + "accessed before the operation has occurred.") ;
+ }
+
+ return m_principal ;
+ }
+
+
+ /**
+ * Sets the user principal that has just bound a session with the server.
+ * This event property is only available after the bind operation.
+ *
+ * @param a_principal the authenticated user.
+ */
+ public void setPrincipal(Principal a_principal)
+ {
+ if(null == m_principal) {
+ m_principal = a_principal ;
+ } else {
+ throw new IllegalStateException("Prinicipal change via "
+ + "setPrincipal() after propertiy initialization not allowed. "
+ + "\nsetPrincipal() can be called at most once.") ;
+ }
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/CompareEvent.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/CompareEvent.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,179 @@
+/*
+ * $Id: CompareEvent.java,v 1.3 2003/03/13 18:27:26 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.event.protocol ;
+
+
+import javax.naming.Name ;
+import javax.naming.directory.Attributes ;
+
+
+/**
+ * Event which logically represents a protocol compare operation. The events
+ * properties are all initialized for both the before and after event firings
+ * available to both event listener methods. Alteration attempts to event
+ * properties result in a IllegalStateException since they can only be set once.
+ */
+public class CompareEvent
+ extends ProtocolEvent
+{
+ /** The Dn of the entry compared */
+ private Name m_dn = null ;
+ /** The attributes in the entry whose values are compared. */
+ private Attributes m_attributes = null ;
+ /** The name of the attribute to compare */
+ private String m_attrId = null ;
+ /** The value to use in the attribute comparison */
+ private Object m_attrValue = null ;
+
+
+ /**
+ * Creates a baseline uninitialized ComareEvent.
+ *
+ * @param a_src the source of the event.
+ * @param a_isPduDelivered whether or not an actual physical compare pdu
+ * caused this event.
+ */
+ public CompareEvent(Object a_src, boolean a_isPduDelivered)
+ {
+ super(a_src, COMPAREREQUEST_MASK, a_isPduDelivered) ;
+ }
+
+
+ /**
+ * Sets the distinguished name of entry to compare.
+ *
+ * @param a_dn the distinguished name of the entry to compare.
+ */
+ public void setName(Name a_dn)
+ {
+ if(null == m_dn) {
+ m_dn = a_dn ;
+ } else {
+ throw new IllegalStateException("Can't call setName() more than "
+ + "once!") ;
+ }
+ }
+
+
+ /**
+ * Gets the distinguished name of the entry to compare.
+ *
+ * @return the dn of the entry to compare.
+ */
+ public Name getName()
+ {
+ if(null == m_dn) {
+ throw new IllegalStateException("CompareEvent has not been properly "
+ + "initialized!") ;
+ }
+
+ return m_dn ;
+ }
+
+
+ /**
+ * Gets the Attributes of the entry is about to be compared.
+ * This property is available for both before and after operations event
+ * firings.
+ *
+ * @return the entry Attributes
+ */
+ public Attributes getAttributes()
+ {
+ if(null == m_attributes) {
+ throw new IllegalStateException("CompareEvent has not been properly "
+ + "initialized!") ;
+ }
+
+ return m_attributes ;
+ }
+
+
+ /**
+ * Sets the events attributes for the entry that is about to or already has
+ * been compared by the server. This property is available for both before
+ * and after operation event firings.
+ *
+ * @param a_attributes the attributes for the compared entry.
+ */
+ public void setAttributes(Attributes a_attributes)
+ {
+ if(null == m_attributes) {
+ m_attributes = a_attributes ;
+ } else {
+ throw new IllegalStateException("The attributes of this event "
+ + " may only be set at most one time.") ;
+ }
+ }
+
+
+ /**
+ * Gets the value of the attribute to use in this comparison.
+ *
+ * @return the value of the attribute to compare with the entry.
+ */
+ public Object getAttributeValue()
+ {
+ if(null == m_attrValue) {
+ throw new IllegalStateException("CompareEvent has not been properly"
+ + " initialized!") ;
+ }
+
+ return this.m_attrValue ;
+ }
+
+
+ /**
+ * Gets the name or Id of the attribute used in this comparison.
+ *
+ * @return the name or id of the comparison attribute.
+ */
+ public String getAttributeId()
+ {
+ if(null == m_attrId) {
+ throw new IllegalStateException("CompareEvent has not been properly"
+ + " initialized!") ;
+ }
+
+ return this.m_attrId ;
+ }
+
+
+ /**
+ * Sets the value of the attribute to use in this comparison.
+ *
+ * @param a_value the value of the attribute to compare with the entry.
+ */
+ public void setAttributeValue(Object a_value)
+ {
+ if(null == m_attrValue) {
+ m_attrValue = a_value ;
+ } else {
+ throw new IllegalStateException("The attributes of this event "
+ + " may only be set at most one time.") ;
+ }
+ }
+
+
+ /**
+ * Sets the name or Id of the attribute used in this comparison.
+ *
+ * @return the name or id of the comparison attribute.
+ */
+ public void setAttributeId(String a_attrId)
+ {
+ if(null == m_attrId) {
+ m_attrId = a_attrId ;
+ } else {
+ throw new IllegalStateException("The attributes of this event "
+ + " may only be set at most one time.") ;
+ }
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/DelEvent.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/DelEvent.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,109 @@
+/*
+ * $Id: DelEvent.java,v 1.3 2003/03/13 18:27:26 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.event.protocol ;
+
+
+import javax.naming.Name ;
+import javax.naming.directory.Attributes ;
+
+
+/**
+ * Event which logically represents a protocol del operation.
+ */
+public class DelEvent
+ extends ProtocolEvent
+{
+ /** The distinguished name of the entry to remove. */
+ private Name m_dn = null ;
+ /** The attributes of the entry to remove */
+ private Attributes m_attributes = null ;
+
+
+ /**
+ * Creates an uninitialized DelEvent.
+ *
+ * @param a_src the source of the event.
+ * @param a_isPduDelivered true if this event represents a physical PDU
+ * delivery or is a logical representation of the operation through the
+ * JNDI provider.
+ */
+ public DelEvent(Object a_src, boolean a_isPduDelivered)
+ {
+ super(a_src, DELREQUEST_MASK, a_isPduDelivered) ;
+ }
+
+
+ /**
+ * Sets the distinguished name of entry to remove.
+ *
+ * @param a_dn the distinguished name of the entry to remove.
+ */
+ public void setName(Name a_dn)
+ {
+ if(null == m_dn) {
+ m_dn = a_dn ;
+ } else {
+ throw new IllegalStateException("Can't call setName() more than "
+ + "once!") ;
+ }
+ }
+
+
+ /**
+ * Gets the distinguished name of the entry to remove.
+ *
+ * @return the dn of the entry to remove.
+ */
+ public Name getName()
+ {
+ if(null == m_dn) {
+ throw new IllegalStateException("DelEvent has not been properly "
+ + "initialized!") ;
+ }
+
+ return m_dn ;
+ }
+
+
+ /**
+ * Gets the Attributes of the entry is about to be removed or was removed.
+ * This property is available for both before and after operations event
+ * firings.
+ *
+ * @return the entry Attributes
+ */
+ public Attributes getAttributes()
+ {
+ if(null == m_attributes) {
+ throw new IllegalStateException("DelEvent has not been properly "
+ + "initialized!") ;
+ }
+
+ return m_attributes ;
+ }
+
+
+ /**
+ * Sets the events attributes for the entry that is about to or already has
+ * been deleted from the server. This property is available for both before
+ * and after operations event firings.
+ *
+ * @param a_attributes the attributes for the deleted entry.
+ */
+ public void setAttributes(Attributes a_attributes)
+ {
+ if(null == m_attributes) {
+ m_attributes = a_attributes ;
+ } else {
+ throw new IllegalStateException("The attributes of this event "
+ + " may only be set at most one time.") ;
+ }
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/EventManager.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/EventManager.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,65 @@
+/*
+ * $Id: EventManager.java,v 1.3 2003/03/13 18:27:26 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.event.protocol ;
+
+
+/**
+ * The service interface for a synchronous protocol event manager.
+ */
+public interface EventManager
+{
+ /** The ROLE is the fully qualified name of this interface */
+ public static final String ROLE = EventManager.class.getName() ;
+
+ /**
+ * Synchronously fires a protocol event calling the event handler of all
+ * registered listeners for the event type of a_event after the operatation
+ * successfully takes place.
+ *
+ * @param a_event the event to fire after the operation
+ */
+ void fireAfter(ProtocolEvent a_event) ;
+
+ /**
+ * Synchronously fires a protocol event calling the event handler of all
+ * registered listeners for the event type of a_event before the operatation
+ * takes place.
+ *
+ * @param a_event the event to fire before the operation
+ */
+ void fireBefore(ProtocolEvent a_event) ;
+
+ /**
+ * Checks to see if a listener is registered for event delivery of this
+ * kind specified by a_mask.
+ */
+ boolean hasListener(int a_mask) ;
+
+ /**
+ * Adds a protocol event listener registering it for events that would be
+ * accepted by a_mask.
+ *
+ * @param a_listener the protocol listener to register.
+ * @param a_mask used to determine which events the listener will recieve.
+ */
+ void addListener(ProtocolListener a_listener, int a_mask) ;
+
+ /**
+ * Adds a protocol event listener registering it for events that would be
+ * accepted by a_mask.
+ *
+ * @param a_listener the protocol listener to register.
+ * @param a_mask used to determine which events the listener will recieve.
+ * @param whether or not errors in a_listener's event handler are trapped,
+ * trapped errors cannot effect the outcome of the operation.
+ */
+ void addListener(ProtocolListener a_listener, int a_mask,
+ boolean trapErrors) ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/EventModule.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/EventModule.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,327 @@
+/*
+ * $Id: EventModule.java,v 1.5 2003/03/13 18:27:26 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.event.protocol ;
+
+
+import java.util.HashMap ;
+import java.util.Iterator ;
+
+import org.apache.eve.AbstractModule ;
+
+import org.apache.avalon.framework.configuration.Configuration ;
+
+
+/**
+ * Default synchronous event manager implementation for the server.
+ *
+ * @phoenix:block
+ * @phoenix:service name="org.apache.eve.event.protocol.EventManager"
+ * @phoenix:mx-topic name="backend-nexus"
+ */
+public class EventModule
+ extends AbstractModule
+ implements EventManager
+{
+ /** Map of listeners to their Listener spec. */
+ private HashMap m_listeners = new HashMap() ;
+ /**
+ * Current mask used to determine if an event listener of a specific type
+ * is registered to recieve events. This mask is constructed by doing a
+ * comulative bitwise OR on it and the registered event masks of a listener.
+ */
+ private int m_mask = 0 ;
+
+
+ /**
+ * Adds a protocol event listener registering it for events that would be
+ * accepted by a_mask.
+ *
+ * @param a_listener the protocol listener to register.
+ * @param a_mask used to determine which events the listener will recieve.
+ * @param whether or not errors in a_listener's event handler are trapped,
+ * trapped errors cannot effect the outcome of the operation.
+ */
+ public void addListener(ProtocolListener a_listener, int a_mask,
+ boolean trapErrors)
+ {
+ if(!ProtocolEvent.isValid(a_mask)) {
+ throw new IllegalArgumentException("Invalid mask parameter.") ;
+ }
+
+ ListenerSpec l_spec = new ListenerSpec() ;
+ l_spec.mask = a_mask ;
+ l_spec.trapErrors = trapErrors ;
+
+ synchronized(m_listeners) {
+ m_listeners.put(a_listener, l_spec) ;
+ m_mask |= a_mask ;
+ }
+ }
+
+
+ /**
+ * Adds a protocol event listener registering it for events that would be
+ * accepted by a_mask.
+ *
+ * @param a_listener the protocol listener to register.
+ * @param a_mask used to determine which events the listener will recieve.
+ */
+ public void addListener(ProtocolListener a_listener, int a_mask)
+ {
+ if(!ProtocolEvent.isValid(a_mask)) {
+ throw new IllegalArgumentException("Invalid mask parameter.") ;
+ }
+
+ ListenerSpec l_spec = new ListenerSpec() ;
+ l_spec.mask = a_mask ;
+
+ synchronized(m_listeners) {
+ m_listeners.put(a_listener, l_spec) ;
+ m_mask |= a_mask ;
+ }
+ }
+
+
+ public boolean hasListener(int a_mask)
+ {
+ return (m_mask & a_mask) == a_mask ;
+ }
+
+
+ /**
+ * Synchronously fires a protocol event calling the event handler of all
+ * registered listeners for the event type of a_event after the operatation
+ * successfully takes place.
+ *
+ * @param a_event the event to fire after the operation
+ */
+ public void fireAfter(ProtocolEvent a_event)
+ {
+ Iterator l_list = m_listeners.keySet().iterator() ;
+ while(l_list.hasNext()) {
+ ProtocolListener l_listener = (ProtocolListener) l_list.next() ;
+ ListenerSpec l_spec = (ListenerSpec)
+ m_listeners.get(l_listener) ;
+
+ // If the listener is registered for the a_event type
+ if(a_event.accepts(l_spec.mask)) {
+ if(l_spec.trapErrors) {
+ try {
+ afterOn(l_listener, a_event) ;
+ } catch(Throwable t) {
+ super.getLogger().error("Listener " + l_listener
+ + " failed to successfully handle event "
+ + a_event) ;
+ }
+ } else {
+ try {
+ afterOn(l_listener, a_event) ;
+ } catch(RuntimeException re) {
+ throw re ;
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Synchronously fires a protocol event calling the event handler of all
+ * registered listeners for the event type of a_event before the operatation
+ * takes place.
+ *
+ * @param a_event the event to fire before the operation
+ */
+ public void fireBefore(ProtocolEvent a_event)
+ {
+ Iterator l_list = m_listeners.keySet().iterator() ;
+ while(l_list.hasNext()) {
+ ProtocolListener l_listener = (ProtocolListener) l_list.next() ;
+ ListenerSpec l_spec = (ListenerSpec)
+ m_listeners.get(l_listener) ;
+
+ // If the listener is registered for the a_event type
+ if(a_event.accepts(l_spec.mask)) {
+ if(l_spec.trapErrors) {
+ try {
+ beforeOn(l_listener, a_event) ;
+ } catch(Throwable t) {
+ super.getLogger().error("Listener " + l_listener
+ + " failed to successfully handle event "
+ + a_event) ;
+ }
+ } else {
+ try {
+ beforeOn(l_listener, a_event) ;
+ } catch(RuntimeException re) {
+ throw re ;
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Calls the after() method on a_listener using a_event as the argument
+ * using a switch on the event mask to cast the event to the appropriate
+ * event class type.
+ *
+ * @param a_listener to call the after method on
+ * @param a_event the protocol event to use when calling after()
+ */
+ private void afterOn(ProtocolListener a_listener, ProtocolEvent a_event)
+ {
+ switch(a_event.mask) {
+ case(ProtocolEvent.ABANDONREQUEST_MASK):
+ a_listener.after((AbandonEvent) a_event) ;
+ break ;
+ case(ProtocolEvent.ADDREQUEST_MASK):
+ a_listener.after((AddEvent) a_event) ;
+ break ;
+ case(ProtocolEvent.BINDREQUEST_MASK):
+ a_listener.after((BindEvent) a_event) ;
+ break ;
+ case(ProtocolEvent.COMPAREREQUEST_MASK):
+ a_listener.after((CompareEvent) a_event) ;
+ break ;
+ case(ProtocolEvent.DELREQUEST_MASK):
+ a_listener.after((DelEvent) a_event) ;
+ break ;
+ case(ProtocolEvent.EXTENDEDREQ_MASK):
+ a_listener.after((ExtendedEvent) a_event) ;
+ break ;
+ case(ProtocolEvent.MODDNREQUEST_MASK):
+ a_listener.after((ModifyDnEvent) a_event) ;
+ break ;
+ case(ProtocolEvent.MODIFYREQUEST_MASK):
+ a_listener.after((ModifyEvent) a_event) ;
+ break ;
+ case(ProtocolEvent.SEARCHREQUEST_MASK):
+ a_listener.after((SearchEvent) a_event) ;
+ break ;
+ case(ProtocolEvent.UNBINDREQUEST_MASK):
+ a_listener.after((UnbindEvent) a_event) ;
+ break ;
+ default:
+ throw new IllegalArgumentException("Unidentified event mask type "
+ + a_event.mask) ;
+ }
+ }
+
+
+ /**
+ * Calls the before() method on a_listener using a_event as the argument
+ * using a switch on the event mask to cast the event to the appropriate
+ * event class type.
+ *
+ * @param a_listener to call the before method on
+ * @param a_event the protocol event to use when calling before()
+ */
+ private void beforeOn(ProtocolListener a_listener, ProtocolEvent a_event)
+ {
+ switch(a_event.mask) {
+ case(ProtocolEvent.ABANDONREQUEST_MASK):
+ a_listener.before((AbandonEvent) a_event) ;
+ break ;
+ case(ProtocolEvent.ADDREQUEST_MASK):
+ a_listener.before((AddEvent) a_event) ;
+ break ;
+ case(ProtocolEvent.BINDREQUEST_MASK):
+ a_listener.before((BindEvent) a_event) ;
+ break ;
+ case(ProtocolEvent.COMPAREREQUEST_MASK):
+ a_listener.before((CompareEvent) a_event) ;
+ break ;
+ case(ProtocolEvent.DELREQUEST_MASK):
+ a_listener.before((DelEvent) a_event) ;
+ break ;
+ case(ProtocolEvent.EXTENDEDREQ_MASK):
+ a_listener.before((ExtendedEvent) a_event) ;
+ break ;
+ case(ProtocolEvent.MODDNREQUEST_MASK):
+ a_listener.before((ModifyDnEvent) a_event) ;
+ break ;
+ case(ProtocolEvent.MODIFYREQUEST_MASK):
+ a_listener.before((ModifyEvent) a_event) ;
+ break ;
+ case(ProtocolEvent.SEARCHREQUEST_MASK):
+ a_listener.before((SearchEvent) a_event) ;
+ break ;
+ case(ProtocolEvent.UNBINDREQUEST_MASK):
+ a_listener.before((UnbindEvent) a_event) ;
+ break ;
+ default:
+ throw new IllegalArgumentException("Unidentified event mask type "
+ + a_event.mask) ;
+ }
+ }
+
+
+ /** Crap */
+ class ListenerSpec {
+ int mask = 0 ;
+ boolean trapErrors = false ;
+ }
+
+
+ ////////////////////
+ // Module Methods //
+ ////////////////////
+
+
+ /**
+ * Gets the service interface (a.k.a ROLE) used by this module.
+ *
+ * @return the ROLE of this module.
+ */
+ public String getImplementationRole()
+ {
+ return ROLE ;
+ }
+
+
+ /**
+ * Gets a descriptive name for this module.
+ *
+ * @return the descriptive name for this module.
+ */
+ public String getImplementationName()
+ {
+ return "Protocol Event Module" ;
+ }
+
+
+ /**
+ * Gets the implementing class name of this module.
+ *
+ * @return the name of this module's class.
+ */
+ public String getImplementationClassName()
+ {
+ return this.getClass().getName() ;
+ }
+
+
+ //////////////////////////////
+ // Avalon Lifecycle Methods //
+ //////////////////////////////
+
+
+ /**
+ * Module configuration life-cycle method.
+ *
+ * @param a_config the block level configuration for this module
+ */
+ public void configure(Configuration a_config)
+ {
+ // Does nothing ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/ExtendedEvent.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/ExtendedEvent.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,104 @@
+/*
+ * $Id: ExtendedEvent.java,v 1.3 2003/03/13 18:27:27 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.event.protocol ;
+
+
+import java.util.EventObject ;
+
+
+/**
+ * Event which logically represents a protocol extended operation.
+ */
+public class ExtendedEvent
+ extends ProtocolEvent
+{
+ /** The OID of the extended operation */
+ private String m_oid = null ;
+ /** The binary payload of the extended request */
+ private byte [] m_payload = null ;
+
+
+ /**
+ * Creates an uninitialized ExtendedEvent.
+ *
+ * @param a_src the source of the event.
+ * @param a_isPduDelivered true if this event represents a physical PDU
+ * delivery or is a logical representation of the operation through the
+ * JNDI provider.
+ */
+ public ExtendedEvent(Object a_src, boolean a_isPduDelivered)
+ {
+ super(a_src, EXTENDEDREQ_MASK, a_isPduDelivered) ;
+ }
+
+
+ /**
+ * Gets the extended operation's Oid.
+ *
+ * @return the OID of the extended operation.
+ */
+ public String getOid()
+ {
+ if(null == m_oid) {
+ throw new IllegalStateException("ExtendedEvent has not been "
+ + "properly initialized!") ;
+ }
+
+ return m_oid ;
+ }
+
+
+ /**
+ * Sets the extended operation's Oid.
+ *
+ * @param a_oid the OID of the extended operation.
+ */
+ public void setOid(String a_oid)
+ {
+ if(null == m_oid) {
+ m_oid = a_oid ;
+ } else {
+ throw new IllegalStateException("Can't call setOid() more than "
+ + "once!") ;
+ }
+ }
+
+
+ /**
+ * Gets the payload of the extended operation.
+ *
+ * @return the payload of the extended request
+ */
+ public byte [] getPayload()
+ {
+ if(null == m_payload) {
+ throw new IllegalStateException("ExtendedEvent has not been "
+ + "properly initialized!") ;
+ }
+
+ return m_payload ;
+ }
+
+
+ /**
+ * Sets the payload of the extended operation.
+ *
+ * @param a_payload the payload of the extended request
+ */
+ public void setPayload(byte [] a_payload)
+ {
+ if(null == m_payload) {
+ m_payload = a_payload ;
+ } else {
+ throw new IllegalStateException("Can't call setPayload() more than "
+ + "once!") ;
+ }
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/ModifyDnEvent.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/ModifyDnEvent.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,174 @@
+/*
+ * $Id: ModifyDnEvent.java,v 1.3 2003/03/13 18:27:27 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.event.protocol ;
+
+
+import java.util.EventObject ;
+import javax.naming.Name;
+import javax.naming.directory.Attributes;
+
+
+/**
+ * Event which logically represents a protocol modifyDn operation.
+ */
+public class ModifyDnEvent
+ extends ProtocolEvent
+{
+ /** The distinguished name of the entry modified. */
+ private Name m_dn = null ;
+ /** The new relative distinguished name of the entry modified. */
+ private Name m_rdn = null ;
+ /** The new base distinguished name of the entry to be moved. */
+ private Name m_newBase = null ;
+ /** The attributes of the entry being modified. */
+ private Attributes m_attributes = null ;
+
+
+ /**
+ * Creates an uninitialized ModifyDnEvent.
+ */
+ public ModifyDnEvent(Object a_src, boolean a_isPduDelivered)
+ {
+ super(a_src, MODDNREQUEST_MASK, a_isPduDelivered) ;
+ }
+
+
+ /**
+ * Sets the distinguished name of entry to move.
+ *
+ * @param a_dn the distinguished name of the entry to move.
+ */
+ public void setName(Name a_dn)
+ {
+ if(null == m_dn) {
+ m_dn = a_dn ;
+ } else {
+ throw new IllegalStateException("Can't call setName() more than "
+ + "once!") ;
+ }
+ }
+
+
+ /**
+ * Gets the distinguished name of the entry to change the dn of.
+ *
+ * @return the dn of the entry to move.
+ */
+ public Name getName()
+ {
+ if(null == m_dn) {
+ throw new IllegalStateException("ModifyDnEvent has not been"
+ + "properly initialized!") ;
+ }
+
+ return m_dn ;
+ }
+
+
+ /**
+ * Sets the new relative name of entry to move.
+ *
+ * @param a_rdn the relative name of the entry to move.
+ */
+ public void setRdn(Name a_rdn)
+ {
+ if(null == m_rdn) {
+ m_rdn = a_rdn ;
+ } else {
+ throw new IllegalStateException("Can't call setRdn() more than "
+ + "once!") ;
+ }
+ }
+
+
+ /**
+ * Gets the relative name of the entry to change the dn of.
+ *
+ * @return the rdn of the entry to move.
+ */
+ public Name getRdn()
+ {
+ if(null == m_rdn) {
+ throw new IllegalStateException("ModifyDnEvent has not been"
+ + "properly initialized!") ;
+ }
+
+ return m_rdn ;
+ }
+
+
+ /**
+ * Sets the distinguished name of entry to move.
+ *
+ * @param a_newBase the distinguished name of the entry to move.
+ */
+ public void setBaseName(Name a_newBase)
+ {
+ if(null == m_dn) {
+ m_newBase = a_newBase ;
+ } else {
+ throw new IllegalStateException("Can't call setBaseName() more than"
+ + " once!") ;
+ }
+ }
+
+
+ /**
+ * Gets the new base distinguished name of the entry to move the entry
+ * under.
+ *
+ * @return the base dn to move the entry to.
+ */
+ public Name getBaseName()
+ {
+ if(null == m_newBase) {
+ throw new IllegalStateException("ModifyDnEvent has not been"
+ + "properly initialized!") ;
+ }
+
+ return m_newBase ;
+ }
+
+
+ /**
+ * Gets the Attributes of the entry is about to have its DN modified.
+ * This property is available for both before and after operations event
+ * firings.
+ *
+ * @return the entry Attributes
+ */
+ public Attributes getAttributes()
+ {
+ if(null == m_attributes) {
+ throw new IllegalStateException("ModifyDnEvent has not been"
+ + "properly initialized!") ;
+ }
+
+ return m_attributes ;
+ }
+
+
+ /**
+ * Sets the events attributes for the entry that is about to or already has
+ * been modified by the server. This property is available for both before
+ * and after operations event firings.
+ *
+ * @param a_attributes the attributes for the modified entry.
+ */
+ public void setAttributes(Attributes a_attributes)
+ {
+ if(null == m_attributes) {
+ m_attributes = a_attributes ;
+ } else {
+ throw new IllegalStateException("The attributes of this event "
+ + " may only be set at most one time.") ;
+ }
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/ModifyEvent.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/ModifyEvent.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,148 @@
+/*
+ * $Id: ModifyEvent.java,v 1.3 2003/03/13 18:27:28 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.event.protocol ;
+
+
+import javax.naming.Name ;
+import javax.naming.directory.Attributes ;
+import javax.naming.directory.ModificationItem ;
+
+
+/**
+ * Event which logically represents a protocol modify operation.
+ */
+public class ModifyEvent
+ extends ProtocolEvent
+{
+ /** The distinguished name of the entry to modify. */
+ private Name m_dn = null ;
+ /** The attributes of the entry to modify */
+ private Attributes m_attributes = null ;
+ /** The modifications made or to be made on the entry */
+ private ModificationItem [] m_mods = null ;
+
+
+ /**
+ * Creates an uninitialized ModifyEvent.
+ *
+ * @param a_src the source of the event.
+ * @param a_isPduDelivered true if this event represents a physical PDU
+ * delivery or is a logical representation of the operation through the
+ * JNDI provider.
+ */
+ public ModifyEvent(Object a_src, boolean a_isPduDelivered)
+ {
+ super(a_src, MODIFYREQUEST_MASK, a_isPduDelivered) ;
+ }
+
+
+ /**
+ * Sets the distinguished name of entry to modified.
+ *
+ * @param a_dn the distinguished name of the entry to modified.
+ */
+ public void setName(Name a_dn)
+ {
+ if(null == m_dn) {
+ m_dn = a_dn ;
+ } else {
+ throw new IllegalStateException("Can't call setName() more than "
+ + "once!") ;
+ }
+ }
+
+
+ /**
+ * Gets the distinguished name of the entry to modified.
+ *
+ * @return the dn of the entry to remove.
+ */
+ public Name getName()
+ {
+ if(null == m_dn) {
+ throw new IllegalStateException("ModifyEvent has not been properly "
+ + "initialized!") ;
+ }
+
+ return m_dn ;
+ }
+
+
+ /**
+ * Gets the Attributes of the entry is about to be modified or was modified.
+ * This property is available for both before and after operations event
+ * firings.
+ *
+ * @return the entry Attributes
+ */
+ public Attributes getAttributes()
+ {
+ if(null == m_attributes) {
+ throw new IllegalStateException("ModifyEvent has not been properly "
+ + "initialized!") ;
+ }
+
+ return m_attributes ;
+ }
+
+
+ /**
+ * Sets the events attributes for the entry that is about to or already has
+ * been modified by the server. This property is available for both before
+ * and after operations event firings.
+ *
+ * @param a_attributes the attributes for the modified entry.
+ */
+ public void setAttributes(Attributes a_attributes)
+ {
+ if(null == m_attributes) {
+ m_attributes = a_attributes ;
+ } else {
+ throw new IllegalStateException("The attributes of this event "
+ + " may only be set at most one time.") ;
+ }
+ }
+
+
+ /**
+ * Gets the Modifications on the entry that is about to be modified or was
+ * modified. This property is available for both before and after
+ * operations event firings.
+ *
+ * @return the entry ModificationItems
+ */
+ public ModificationItem [] getModifications()
+ {
+ if(null == m_mods) {
+ throw new IllegalStateException("ModifyEvent has not been properly "
+ + "initialized!") ;
+ }
+
+ return m_mods ;
+ }
+
+
+ /**
+ * Sets the event's modifications on the entry that is about to or already
+ * has been modified by the server. This property is available for both
+ * before and after operations event firings.
+ *
+ * @param a_mods the attributes for the modified entry.
+ */
+ public void setModifications(ModificationItem [] a_mods)
+ {
+ if(null == m_mods) {
+ m_mods = a_mods ;
+ } else {
+ throw new IllegalStateException("The modification of this event "
+ + " may only be set at most one time.") ;
+ }
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/ProtocolAdapter.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/ProtocolAdapter.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,55 @@
+/*
+ * $Id: ProtocolAdapter.java,v 1.2 2003/03/13 18:27:28 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.event.protocol ;
+
+
+public class ProtocolAdapter
+ implements ProtocolListener
+{
+ public void after(UnbindEvent a_event) { }
+
+ public void after(SearchEvent a_event) { }
+
+ public void after(ModifyDnEvent a_event) { }
+
+ public void after(ModifyEvent a_event) { }
+
+ public void after(ExtendedEvent a_event) { }
+
+ public void after(DelEvent a_event) { }
+
+ public void after(CompareEvent a_event) { }
+
+ public void after(BindEvent a_event) { }
+
+ public void after(AddEvent a_event) { }
+
+ public void after(AbandonEvent a_event) { }
+
+ public void before(UnbindEvent a_event) { }
+
+ public void before(SearchEvent a_event) { }
+
+ public void before(ModifyDnEvent a_event) { }
+
+ public void before(ModifyEvent a_event) { }
+
+ public void before(ExtendedEvent a_event) { }
+
+ public void before(DelEvent a_event) { }
+
+ public void before(CompareEvent a_event) { }
+
+ public void before(BindEvent a_event) { }
+
+ public void before(AddEvent a_event) { }
+
+ public void before(AbandonEvent a_event) { }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/ProtocolEvent.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/ProtocolEvent.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,188 @@
+/*
+ * $Id: ProtocolEvent.java,v 1.3 2003/03/13 18:27:29 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.event.protocol ;
+
+
+import java.util.EventObject ;
+
+
+/**
+ * Event which logically represents a protocol unbind operation.
+ */
+public class ProtocolEvent
+ extends EventObject
+{
+ /** Bind request type mask */
+ public static final int BINDREQUEST_MASK = 0x40000000 ;
+ /** Unbind request type mask */
+ public static final int UNBINDREQUEST_MASK = 0x40000002 ;
+ /** Search request type mask */
+ public static final int SEARCHREQUEST_MASK = 0x40000003 ;
+ /** Modify request type mask */
+ public static final int MODIFYREQUEST_MASK = 0x40000006 ;
+ /** Add request type mask */
+ public static final int ADDREQUEST_MASK = 0x40000008 ;
+ /** Del request type mask */
+ public static final int DELREQUEST_MASK = 0x4000000a ;
+ /** Modify Dn request type mask */
+ public static final int MODDNREQUEST_MASK = 0x4000000c ;
+ /** Compare request type mask */
+ public static final int COMPAREREQUEST_MASK = 0x4000000e ;
+ /** Abandon request type mask */
+ public static final int ABANDONREQUEST_MASK = 0x40000010 ;
+ /** Extended request type mask */
+ public static final int EXTENDEDREQ_MASK = 0x40000017 ;
+
+ /** A [] of all the event type masks */
+ private final static int list[] = { BINDREQUEST_MASK, UNBINDREQUEST_MASK,
+ SEARCHREQUEST_MASK, MODIFYREQUEST_MASK, ADDREQUEST_MASK,
+ DELREQUEST_MASK, MODDNREQUEST_MASK, COMPAREREQUEST_MASK,
+ ABANDONREQUEST_MASK, EXTENDEDREQ_MASK } ;
+
+ /**
+ * A super mask accepting any event generated by bitwise ORing all the
+ * defined event mask's. This mask will always return true on calls to
+ * accepts regardless of the event type.
+ */
+ public static final int ALL_MASK =
+ ABANDONREQUEST_MASK | ADDREQUEST_MASK | BINDREQUEST_MASK |
+ COMPAREREQUEST_MASK | DELREQUEST_MASK | EXTENDEDREQ_MASK |
+ MODDNREQUEST_MASK | MODDNREQUEST_MASK | SEARCHREQUEST_MASK |
+ UNBINDREQUEST_MASK ;
+
+
+ /**
+ * Checks to see if a mask is composed of valid mask event values.
+ *
+ * @param mask the mask value to verify.
+ * @return true if the mask is composed of valid event mask values, false
+ * otherwise.
+ */
+ public static boolean isValid(int mask)
+ {
+ return (ALL_MASK & mask) == mask ;
+ }
+
+
+ /**
+ * Checks to see if a event mask type value is defined.
+ *
+ * @param mask the type mask value to verify.
+ * @throws IllegalArgumentException if the mask is not valid.
+ */
+ public static void checkEventType(int mask)
+ {
+ switch(mask) {
+ case(ABANDONREQUEST_MASK):
+ break ;
+ case(ADDREQUEST_MASK):
+ break ;
+ case(BINDREQUEST_MASK):
+ break ;
+ case(COMPAREREQUEST_MASK):
+ break ;
+ case(DELREQUEST_MASK):
+ break ;
+ case(EXTENDEDREQ_MASK):
+ break ;
+ case(MODDNREQUEST_MASK):
+ break ;
+ case(MODIFYREQUEST_MASK):
+ break ;
+ case(SEARCHREQUEST_MASK):
+ break ;
+ case(UNBINDREQUEST_MASK):
+ break ;
+ default:
+ throw new IllegalArgumentException("Could not recognize protocol "
+ + "event operation mask value of " + mask) ;
+ }
+ }
+
+
+ //////////////////////
+ // Member Variables //
+ //////////////////////
+
+
+ /** The type mask for this event */
+ public final int mask ;
+ /** Whether or not this event represents the physical delivery of a PDU */
+ public final boolean pduDelivered ;
+
+
+ /**
+ * Creates a logical protocol event representing a protocol operation.
+ *
+ * @param a_src the source triggering this event (the caller?)
+ * @param a_mask the event mask used to identify this event type.
+ * @param a_pduDelivered true if this event is to represent the delivery of
+ * a physical PDU for this protocol operation.
+ */
+ ProtocolEvent(Object a_src, int a_mask, boolean a_pduDelivered)
+ {
+ super(a_src) ;
+ mask = a_mask ;
+ pduDelivered = a_pduDelivered ;
+ checkEventType(mask) ;
+ }
+
+
+ /**
+ * Gets whether or not the actual protocol data unit request for an unbind
+ * operation was issued againts the server via the protocol handler. If
+ * this is false the session may have been terminated due to timeout or as
+ * a result of a client server error.
+ *
+ * @return true if the actual unbind pdu was delivered, false otherwise.
+ */
+ public boolean getPduDelivered()
+ {
+ return pduDelivered ;
+ }
+
+
+ /**
+ * Gets whether or not the actual protocol data unit request for an unbind
+ * operation was issued againts the server via the protocol handler. If
+ * this is false the session may have been terminated due to timeout or as
+ * a result of a client server error.
+ *
+ * @return true if the actual unbind pdu was delivered, false otherwise.
+ */
+ public boolean isPduDelivered()
+ {
+ return pduDelivered ;
+ }
+
+
+ /**
+ * Returns whether or not an event mask argument accepts this event
+ * type.
+ *
+ * @param a_mask the mask to test for a match against this event type.
+ * @return true if the mask matches for this event type, false otherwise.
+ */
+ public boolean accepts(int a_mask)
+ {
+ return ((mask & a_mask) == mask) ;
+ }
+
+
+ /**
+ * Gets the event mask type of this event.
+ *
+ * @return the event mask type.
+ */
+ public int getMask()
+ {
+ return mask ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/ProtocolListener.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/ProtocolListener.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,45 @@
+/*
+ * $Id: ProtocolListener.java,v 1.2 2003/03/13 18:27:29 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.event.protocol ;
+
+
+public interface ProtocolListener
+ extends java.util.EventListener
+{
+ void before(AbandonEvent a_event) ;
+ void after(AbandonEvent a_event) ;
+
+ void before(AddEvent a_event) ;
+ void after(AddEvent a_event) ;
+
+ void before(BindEvent a_event) ;
+ void after(BindEvent a_event) ;
+
+ void before(CompareEvent a_event) ;
+ void after(CompareEvent a_event) ;
+
+ void before(DelEvent a_event) ;
+ void after(DelEvent a_event) ;
+
+ void before(ExtendedEvent a_event) ;
+ void after(ExtendedEvent a_event) ;
+
+ void before(ModifyEvent a_event) ;
+ void after(ModifyEvent a_event) ;
+
+ void before(ModifyDnEvent a_event) ;
+ void after(ModifyDnEvent a_event) ;
+
+ void before(SearchEvent a_event) ;
+ void after(SearchEvent a_event) ;
+
+ void before(UnbindEvent a_event) ;
+ void after(UnbindEvent a_event) ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/SearchEvent.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/SearchEvent.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,143 @@
+/*
+ * $Id: SearchEvent.java,v 1.3 2003/03/13 18:27:29 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.event.protocol ;
+
+
+import javax.naming.Name ;
+import javax.naming.directory.Attributes ;
+import javax.naming.directory.SearchControls ;
+import org.apache.ldap.common.filter.ExprNode ;
+
+
+/**
+ * Event which logically represents a protocol search operation.
+ */
+public class SearchEvent
+ extends ProtocolEvent
+{
+ /** The search base as a name */
+ private Name m_base = null ;
+ /** The search filter as an expression tree or AST */
+ private ExprNode m_filter = null ;
+ /** The attributes of the search base */
+ private Attributes m_attributes = null ;
+ /** The search controls associated with the search */
+ private SearchControls m_controls = null ;
+
+
+ /**
+ * Creates an uninitialized SearchEvent.
+ *
+ * @param a_src the source of the event.
+ * @param a_isPduDelivered true if this event represents a physical PDU
+ * delivery or is a logical representation of the operation through the
+ * JNDI provider.
+ */
+ public SearchEvent(Object a_src, boolean a_isPduDelivered)
+ {
+ super(a_src, SEARCHREQUEST_MASK, a_isPduDelivered) ;
+ }
+
+
+ /**
+ * Sets the distinguished name of search base.
+ *
+ * @param a_base the distinguished name of the search base.
+ */
+ public void setBase(Name a_base)
+ {
+ if(null == m_base) {
+ m_base = a_base ;
+ } else {
+ throw new IllegalStateException("Can't call setBase() more than "
+ + "once!") ;
+ }
+ }
+
+
+ /**
+ * Gets the distinguished name of the search base.
+ *
+ * @return the dn of the search base.
+ */
+ public Name getBase()
+ {
+ if(null == m_base) {
+ throw new IllegalStateException("SearchEvent has not been properly "
+ + "initialized!") ;
+ }
+
+ return m_base ;
+ }
+
+
+ /**
+ * Gets the root ExprNode for the search filter as a AST.
+ *
+ * @return the root ExprNode
+ */
+ public ExprNode getFilter()
+ {
+ if(null == m_filter) {
+ throw new IllegalStateException("SearchEvent has not been properly "
+ + "initialized!") ;
+ }
+
+ return m_filter ;
+ }
+
+
+ /**
+ * Sets the root ExprNode for the search filter as a AST.
+ *
+ * @param a_filter the root ExprNode
+ */
+ public void setFilter(ExprNode a_filter)
+ {
+ if(null == m_filter) {
+ m_filter = a_filter ;
+ } else {
+ throw new IllegalStateException("The filter of this event "
+ + " may only be set at most one time.") ;
+ }
+ }
+
+
+ /**
+ * Gets the specific search controls associated with this search operation.
+ *
+ * @return the search controls for this search.
+ */
+ public SearchControls getSearchControls()
+ {
+ if(null == m_controls) {
+ throw new IllegalStateException("SearchEvent has not been properly "
+ + "initialized!") ;
+ }
+
+ return m_controls ;
+ }
+
+
+ /**
+ * Sets the specific search controls associated with this search operation.
+ *
+ * @param a_ctls the search controls associated with this search operation
+ */
+ public void setSearchControls(SearchControls a_ctls)
+ {
+ if(null == m_controls) {
+ m_controls = a_ctls ;
+ } else {
+ throw new IllegalStateException("The search controls of this event "
+ + " may only be set at most one time.") ;
+ }
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/UnbindEvent.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/event/protocol/UnbindEvent.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,23 @@
+/*
+ * $Id: UnbindEvent.java,v 1.2 2003/03/13 18:27:30 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.event.protocol ;
+
+
+/**
+ * Event which logically represents a protocol unbind operation.
+ */
+public class UnbindEvent
+ extends ProtocolEvent
+{
+ public UnbindEvent(Object a_src, boolean pduDelivered)
+ {
+ super(a_src, UNBINDREQUEST_MASK, pduDelivered) ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/input/InputManager.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/input/InputManager.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,46 @@
+/*
+ * $Id: InputManager.java,v 1.4 2003/03/13 18:27:30 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.input ;
+
+
+import java.io.InputStream ;
+import org.apache.eve.client.ClientKey ;
+import org.apache.eve.client.ClientManagerSlave ;
+
+
+/**
+ * Service interface for server module that monitors incomming PDU requests on
+ * a single client InputStream. Only one stream per client can be registered
+ * for input detection. This service pervents a cyclic component dependency by
+ * extending the ClientManagerSlave interface.
+ */
+public interface InputManager
+ extends ClientManagerSlave
+{
+ /** Role played by this service as specified by Avalon */
+ public static final String ROLE = InputManager.class.getName() ;
+
+ /**
+ * Registers a client with this module so that input detection can occur.
+ *
+ * @param a_clientKey the unique key identifing a client
+ * @param a_clientIn the client InputStream to be monitored.
+ */
+ void register(ClientKey a_clientKey, InputStream a_clientIn) ;
+
+ /**
+ * Unregisters a client with this module so that input detection is not
+ * enabled for a client's InputStream previously enabled via the register
+ * method of this service.
+ *
+ * @param a_clientKey the unique key identifing a client
+ */
+ void unregister(ClientKey a_clientKey) ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/input/InputModule.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/input/InputModule.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,260 @@
+/*
+ * $Id: InputModule.java,v 1.7 2003/03/24 13:22:29 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.input ;
+
+
+import java.util.Map ;
+import java.util.HashMap ;
+
+import java.io.InputStream ;
+import java.io.IOException ;
+import java.io.PushbackInputStream ;
+
+import org.apache.eve.AbstractModule ;
+import org.apache.eve.decoder.Decoder ;
+import org.apache.eve.client.ClientKey ;
+import org.apache.eve.event.InputEvent ;
+import org.apache.eve.client.ClientManager ;
+
+import org.apache.avalon.framework.service.ServiceManager ;
+import org.apache.avalon.framework.service.ServiceException ;
+import org.apache.avalon.framework.configuration.Configuration ;
+import org.apache.avalon.cornerstone.services.threads.ThreadManager ;
+import org.apache.avalon.framework.configuration.ConfigurationException ;
+import org.apache.eve.client.KeyExpiryException;
+import org.apache.avalon.framework.logger.Logger;
+
+
+
+
+
+/**
+ * The InputModule implements the InputManager service interface and in
+ * doing so is responsible for detecting input on the client Socket's
+ * InputStream.
+ *
+ * @phoenix:block
+ * @phoenix:mx-topic name="InputModule"
+ * @phoenix:service name="org.apache.eve.input.InputManager"
+ */
+public class InputModule
+ extends AbstractModule
+ implements InputManager
+{
+ /** name of the socket listener pool used for this module: 'client' */
+ public static final String SOCKETLISTENER_POOL = "client" ;
+
+ /** forward map of ClientKeys to client InputStreams */
+ private Map m_streams = new HashMap() ;
+ /** handle on the ClientManager service */
+ private ClientManager m_clientManager = null ;
+ /** handle on the ThreadManager service */
+ private ThreadManager m_threadManager = null ;
+ /** handle on the Decoder service */
+ private Decoder m_decoder = null ;
+
+
+ /**
+ * Registers a client with this module so that input detection can occur.
+ *
+ * @param a_clientKey the unique key identifing a client
+ * @param a_clientIn the client InputStream to be monitored.
+ */
+ public synchronized
+ void register(final ClientKey a_clientKey, final InputStream a_clientIn)
+ {
+ m_streams.put(a_clientKey, a_clientIn) ;
+ Runnable l_monitor = new InputStreamMonitor(a_clientKey, a_clientIn) ;
+ m_threadManager.getThreadPool(SOCKETLISTENER_POOL).execute(l_monitor) ;
+ }
+
+
+ class InputStreamMonitor implements Runnable
+ {
+ final ClientKey m_clientKey ;
+ final InputStream m_clientIn ;
+
+ InputStreamMonitor(final ClientKey a_clientKey,
+ final InputStream a_clientIn)
+ {
+ m_clientKey = a_clientKey ;
+ m_clientIn = a_clientIn ;
+ }
+
+
+ /**
+ * Runnable implementation which monitor's a client connection for
+ * incomming LDAP request data. The loop runs indefinately until the
+ * ClientKey expires or an IOException occurs on the clients
+ * InputStream. IOExceptions drop client connections, log an error and
+ * request that the ClientManager drop the client if it already has not
+ * done so.
+ */
+ public void run() {
+ Logger l_log = InputModule.this.getLogger() ;
+ Object l_lock = null ;
+
+ // Obtain input lock object or return.
+ try {
+ l_lock = m_clientKey.getInputLock() ;
+ } catch(KeyExpiryException e) {
+ if(l_log.isWarnEnabled()) {
+ l_log.warn("ClientKey for " + m_clientKey + " has expired "
+ + "immediately after server accept:", e) ;
+ }
+ return ;
+ }
+
+ // Start input detection loop
+ try {
+ // l_in is used for the life of the connection and hence
+ // this client listener. All InputEvents to the decoder
+ // carry this object.
+ PushbackInputStream l_in =
+ new PushbackInputStream(m_clientIn) ;
+
+ // Character is read then pushed back before event delivery
+ // so the decoder can read a complete PDU with this first byte.
+ int ch = -1 ;
+
+ synchronized(l_lock) {
+ while((ch = l_in.read()) != -1
+ && !m_clientKey.hasExpired())
+ {
+ l_in.unread(ch) ;
+ InputEvent l_event =
+ new InputEvent(m_clientKey, l_in) ;
+ m_decoder.inputReceived(l_event) ;
+
+ try {
+ // Wait until we are notified by event handler
+ // of the decoder to resume listening for more
+ // input from the client. Decoder event handler
+ // needs to suck down a request message before
+ // giving us the io stream back.
+
+ l_lock.wait() ;
+ } catch(InterruptedException e) {
+ m_clientManager.drop(m_clientKey) ;
+ l_log.error("Client " + m_clientKey + " dropped on"
+ + " InputStreamMonitor's thread error: ", e) ;
+ }
+ }
+ }
+ } catch(IOException e) {
+ m_clientManager.drop(m_clientKey) ;
+ l_log.error("Client " + m_clientKey
+ + " dropped due to exception on read from client "
+ + "InputStream: ", e) ;
+ }
+ }
+ }
+
+
+ /**
+ * Unregisters a client with this module so that input detection is not
+ * enabled for a client's InputStream previously enabled via the register
+ * method of this service.
+ *
+ * @param a_clientKey the unique key identifing a client
+ */
+ public synchronized void unregister(ClientKey a_clientKey)
+ {
+ m_streams.remove(a_clientKey) ;
+ }
+
+
+ /**
+ * ClientManagerSlave method implementation which prevents a cyclic
+ * dependency from this module back to the ClientManager. This method sets
+ * the handle on the ClientManager service rather than the <code>service()
+ * </code> lifecycle method.
+ *
+ * @param a_manager the ClientManager service handle
+ */
+ public void registerClientManager(ClientManager a_manager)
+ {
+ m_clientManager = a_manager ;
+ }
+
+
+ /////////////////////////////////
+ // Module & Life-Cycle Methods //
+ /////////////////////////////////
+
+
+ /**
+ * Gets this Module implementation's descriptive name.
+ *
+ * @return descriptive module name
+ * @phoenix:mx-attribute
+ * @phoenix:mx-description gets the descriptive name
+ * @phoenix:mx-isWriteable no
+ */
+ public String getImplementationName()
+ {
+ return "Client Input Manager Module" ;
+ }
+
+
+ /**
+ * Gets this Module implementation's fully qualified class name.
+ *
+ * @return the fqcn
+ * @phoenix:mx-attribute
+ * @phoenix:mx-description gets the FQCN
+ * @phoenix:mx-isWriteable no
+ */
+ public String getImplementationClassName()
+ {
+ return this.getClass().getName() ;
+ }
+
+
+ /**
+ * Gets this Module implementation's service interface (a.k.a its role)
+ *
+ * @return the service interface name
+ * @phoenix:mx-attribute
+ * @phoenix:mx-description gets the service interface (ROLE)
+ * @phoenix:mx-isWriteable no
+ */
+ public String getImplementationRole()
+ {
+ return ROLE ;
+ }
+
+
+ /**
+ * Gets a handle on the Decoder and the ThreadManager services which this
+ * module depends on.
+ *
+ * @phoenix:dependency name="org.apache.eve.decoder.Decoder"
+ * @phoenix:dependency name="org.apache.avalon.cornerstone.services.threads.ThreadManager"
+ */
+ public void service(ServiceManager a_manager)
+ throws ServiceException
+ {
+ super.service(a_manager) ;
+ m_decoder = (Decoder) a_manager.lookup(Decoder.ROLE) ;
+ m_threadManager = (ThreadManager) a_manager.lookup(ThreadManager.ROLE) ;
+ }
+
+
+ /**
+ * Does nothing.
+ *
+ * @param a_config the configuration for this module.
+ */
+ public void configure(Configuration a_config)
+ throws ConfigurationException
+ {
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/jndi/BindingEnumeration.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/jndi/BindingEnumeration.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,139 @@
+/*
+ $Id: BindingEnumeration.java,v 1.3 2003/08/22 21:15:55 akarasulu Exp $
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Jakarta", "Apache Avalon", "Avalon Framework" and
+ "Apache Software Foundation" must not be used to endorse or promote
+ products derived from this software without prior written
+ permission. For written permission, please contact apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package org.apache.eve.jndi ;
+import javax.naming.NamingEnumeration;
+import org.apache.eve.backend.Cursor;
+import javax.naming.NamingException;
+import org.apache.eve.backend.LdapEntry;
+import javax.naming.NameClassPair;
+import org.apache.eve.backend.UnifiedBackend;
+import java.util.Hashtable;
+import org.apache.avalon.framework.ExceptionUtil;
+import javax.naming.Binding;
+
+
+public class BindingEnumeration
+ implements NamingEnumeration
+{
+ private final Hashtable m_env ;
+ private final Cursor m_cursor ;
+
+
+ BindingEnumeration( Hashtable a_env, Cursor a_cursor )
+ {
+ m_env = a_env ;
+ m_cursor = a_cursor ;
+ }
+
+
+ public void close() throws NamingException
+ {
+ m_cursor.close() ;
+ }
+
+
+ public boolean hasMore() throws NamingException
+ {
+ return m_cursor.hasMore() ;
+ }
+
+
+ public Object next() throws NamingException
+ {
+ String l_rdn = null ;
+ String l_class = null ;
+ Object l_obj = null ;
+
+ LdapEntry l_entry = ( LdapEntry ) m_cursor.next() ;
+ if( l_entry.hasAttribute( ContextHelper.JCLASSNAME_ATTR ) )
+ {
+ l_class = ( String )
+ l_entry.getSingleValue( ContextHelper.JCLASSNAME_ATTR ) ;
+ l_obj = ContextHelper.deserialize( l_entry ) ;
+ }
+ else
+ {
+ l_class = UnifiedLdapContext.class.getName() ;
+ l_obj = new UnifiedLdapContext( m_env, l_entry ) ;
+ }
+
+ l_rdn = l_entry.getNormalizedDN().get( 0 ) ;
+ return new Binding( l_rdn, l_class, l_obj ) ;
+ }
+
+
+ public boolean hasMoreElements()
+ {
+ return m_cursor.hasMoreElements() ;
+ }
+
+
+ public Object nextElement()
+ {
+ try
+ {
+ return next() ;
+ }
+ catch( NamingException e )
+ {
+ try
+ {
+ m_cursor.close() ;
+ }
+ catch( Exception e2 )
+ {
+ }
+
+ throw new java.util.NoSuchElementException( "Premature close of "
+ + "backend cursor:\n" + ExceptionUtil.printStackTrace( e ) ) ;
+ }
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/jndi/ContextHelper.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/jndi/ContextHelper.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,728 @@
+/*
+ * $Id: ContextHelper.java,v 1.7 2003/08/22 21:15:55 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.jndi ;
+
+
+import org.apache.ldap.common.name.LdapName ;
+import org.apache.eve.backend.LdapEntry ;
+import org.apache.eve.backend.UnifiedBackend ;
+import org.apache.eve.backend.BackendException ;
+
+import javax.naming.Name ;
+import javax.naming.NamingException ;
+import javax.naming.NameNotFoundException ;
+
+import java.io.IOException ;
+import java.io.ObjectInputStream ;
+import java.io.ObjectOutputStream ;
+import java.io.ByteArrayInputStream ;
+import java.io.ByteArrayOutputStream ;
+import javax.naming.Context;
+import org.apache.ldap.common.util.NamespaceTools;
+import javax.naming.NamingEnumeration;
+import org.apache.eve.backend.Cursor;
+import javax.naming.OperationNotSupportedException;
+
+
+/**
+ * Contains implementation content for the UnifiedContext due to its massive
+ * size.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.7 $
+ */
+public class ContextHelper
+{
+ public static final String TOP_ATTR = "top" ;
+ public static final String JOBJECT_ATTR = "javaObject" ;
+ public static final String OBJECTCLASS_ATTR = "objectClass" ;
+ public static final String JCONTAINER_ATTR = "javaContainer" ;
+ public static final String JSERIALIZEDOBJ_ATTR = "javaSerializedObject" ;
+
+ public static final String JCLASSNAME_ATTR = "javaClassName" ;
+ public static final String JCLASSNAMES_ATTR = "javaClassNames" ;
+ public static final String JSERIALDATA_ATTR = "javaSerializedData" ;
+
+ private final UnifiedContext m_ctx ;
+
+
+
+ /**
+ * Creates a context helper for a UnifiedContext.
+ */
+ ContextHelper( UnifiedContext a_ctx )
+ {
+ m_ctx = a_ctx ;
+ }
+
+
+ public Name composeName( Name a_rdn, Name a_prefix )
+ throws NamingException
+ {
+ LdapEntry l_entry = m_ctx.getEntry() ;
+
+ // Example: This context is ou=people and say name is the relative
+ // name of uid=jwalker and the prefix is dc=domain. Then we must
+ // compose the name relative to prefix which would be:
+ // uid=jwalker,ou=people,dc=domain.
+
+ // To do so we apply the following general algorithm. Find this
+ // context's name relative to the prefix argument: let's call this
+ // the prefix relative name or pfn. Construct the Name of the name
+ // argument and add to this the pfn as the suffix via a Name.addAll().
+
+ // Preliminary Step I: Return the context relative name arg if prefix
+ // is null or is an empty name.
+ if( a_prefix == null || a_prefix.size() == 0 )
+ {
+ return a_rdn ;
+ }
+
+ // Should we check to see if name arg context exists? Or do we presume
+ // that it does and handle failures on context lookups?
+
+ // Step I: Find the prn
+ // Grab last component of the prefix. Find its position in the l_fqn.
+ // Take the prefix of l_fqn upto and including this last component.
+
+ String l_lastComp = a_prefix.get( a_prefix.size() - 1 ) ;
+ Name l_fqn = l_entry.getNormalizedDN() ;
+ Name l_prn = null ;
+ for( int ii = 0 ; ii < l_fqn.size(); ii++ )
+ {
+ if( l_fqn.get( ii ).equals( l_lastComp ) )
+ {
+ l_prn = l_fqn.getPrefix( ii + 1 ) ;
+ break ;
+ }
+ }
+
+ // Step II: Throw exception if l_prn not found which indicates that the
+ // prefix is not an ancestor of this context.
+ if( null == l_prn )
+ {
+ throw new NamingException( "The prefix '" + a_prefix+ "' is not an"
+ + " ancestor of this context '" + l_fqn + "'" ) ;
+ }
+
+ // Step III: Compose the name
+ Name l_retval = new LdapName() ;
+ l_retval.addAll( a_rdn ) ;
+ l_retval.addAll( l_prn ) ;
+ return l_retval ;
+ }
+
+
+ public String composeName( String a_rdn, String a_prefix )
+ throws NamingException
+ {
+ if( a_prefix == null || a_prefix.trim().equals( "" ) )
+ {
+ return a_rdn ;
+ }
+
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ return composeName( l_nexus.getNormalizedName( a_rdn ),
+ l_nexus.getNormalizedName( a_prefix ) ).toString() ;
+ }
+
+
+ public Object lookup( Name a_rdn ) throws NamingException
+ {
+ if( a_rdn.size() == 0 )
+ {
+ return m_ctx.clone() ;
+ }
+
+ Name l_dn = ( Name ) a_rdn.clone() ;
+ LdapEntry l_entry = m_ctx.getEntry() ;
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ l_dn.addAll( l_entry.getNormalizedDN() ) ;
+
+ try
+ {
+ if( l_nexus.hasEntry( l_dn ) )
+ {
+ LdapEntry l_target = l_nexus.read( l_dn ) ;
+
+ if( l_target.hasAttribute( JCLASSNAME_ATTR ) )
+ {
+ return deserialize( l_target ) ;
+ }
+
+ return new UnifiedLdapContext(
+ m_ctx.getEnvironment(), l_target ) ;
+ }
+ }
+ catch( BackendException e )
+ {
+ NamingException l_ne = new NamingException( "Nexus read('" + l_dn
+ + "') failure:\n" + e.getMessage() ) ;
+ l_ne.setRootCause( e ) ;
+ }
+
+ // JNDI NameNotFoundExceptions corresponds to LDAPv3 NOSUCHOBJECT result
+ // code with an enumeration value of [32]
+ throw new NameNotFoundException(
+ "[32] Fully qualified name '" + l_dn
+ + "' for name relative to this context of '" + a_rdn
+ + "' was not found" ) ;
+ }
+
+
+ public Object lookup( String a_rdn ) throws NamingException
+ {
+ if( null == a_rdn || a_rdn.trim().equals( "" ) )
+ {
+ return m_ctx.clone() ;
+ }
+
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ return lookup( l_nexus.getNormalizedName( a_rdn ) ) ;
+ }
+
+
+ public void bind( Name a_rdn, Object an_obj ) throws NamingException
+ {
+ if( an_obj instanceof UnifiedLdapContext )
+ {
+ throw new IllegalArgumentException(
+ "Cannot bind a directory context object!" ) ;
+ }
+
+ Name l_dn = ( Name ) a_rdn.clone() ;
+ LdapEntry l_entry = m_ctx.getEntry() ;
+ LdapEntry l_newEntry = null ;
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ l_dn.addAll( l_entry.getNormalizedDN() ) ;
+
+ try
+ {
+ l_newEntry = l_nexus.newEntry( l_dn.toString() ) ;
+ }
+ catch( BackendException e )
+ {
+ NamingException l_ne = new NamingException( "Failed to get handle "
+ + "on an entry implementation for name '" + a_rdn+ "' due to "
+ + "nexus exception: " ) ;
+ l_ne.setRootCause( e ) ;
+ throw l_ne ;
+ }
+
+ populate( l_newEntry, a_rdn, an_obj ) ;
+
+ try
+ {
+ l_nexus.create( l_newEntry ) ;
+ }
+ catch( BackendException e )
+ {
+ NamingException l_ne = new NamingException("Failed create entry "
+ + "for name '" + a_rdn + "' due to "
+ + "nexus exception. Entry contains:\n" + l_newEntry ) ;
+ l_ne.setRootCause( e ) ;
+ throw l_ne ;
+ }
+ }
+
+
+ public void bind( String a_rdn, Object an_obj) throws NamingException
+ {
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ bind( l_nexus.getNormalizedName( a_rdn ), an_obj ) ;
+ }
+
+
+ public void rebind( Name a_rdn, Object an_obj ) throws NamingException
+ {
+ Name l_dn = new LdapName() ;
+ LdapEntry l_entry = m_ctx.getEntry() ;
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ l_dn.addAll( l_entry.getNormalizedDN() ) ;
+ l_dn.addAll( a_rdn ) ;
+
+ try
+ {
+ if( l_nexus.hasEntry( l_dn ) )
+ {
+ unbind( a_rdn ) ;
+ }
+
+ bind( a_rdn, an_obj ) ;
+ }
+ catch( BackendException e )
+ {
+ NamingException l_ne = new NamingException( "Failed entry lookup "
+ + "for name '" + l_dn + "' due to nexus exception.") ;
+ l_ne.setRootCause(e) ;
+ throw l_ne ;
+ }
+ }
+
+
+ public void rebind( String a_rdn, Object an_obj ) throws NamingException
+ {
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ rebind( l_nexus.getNormalizedName( a_rdn ), an_obj ) ;
+ }
+
+
+ public void unbind( Name a_rdn ) throws NamingException
+ {
+ LdapEntry l_entry = m_ctx.getEntry() ;
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ Name l_dn = new LdapName() ;
+ l_dn.addAll( l_entry.getNormalizedDN() ) ;
+ l_dn.addAll( a_rdn ) ;
+
+ try
+ {
+ if( l_nexus.hasEntry( l_dn ) )
+ {
+ l_nexus.delete( l_entry ) ;
+ }
+ }
+ catch( BackendException e )
+ {
+ NamingException l_ne = new NamingException( "Failed entry deletion "
+ + "for name '" + l_dn + "' due to nexus exception.") ;
+ l_ne.setRootCause( e ) ;
+ throw l_ne ;
+ }
+ }
+
+
+ public void unbind( String a_rdn ) throws NamingException
+ {
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ unbind( l_nexus.getNormalizedName( a_rdn ) ) ;
+ }
+
+
+ public void rename( Name a_oldRdn, Name a_newRdn ) throws NamingException
+ {
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ LdapEntry l_entry = m_ctx.getEntry() ;
+ LdapEntry l_oldEntry = null ;
+ Name l_oldDn = new LdapName() ;
+ Name l_newDn = new LdapName() ;
+ l_oldDn.addAll( l_entry.getNormalizedDN() ) ;
+ l_oldDn.addAll( a_oldRdn ) ;
+ l_newDn.addAll( l_entry.getNormalizedDN() ) ;
+ l_newDn.addAll( a_newRdn ) ;
+
+ try
+ {
+ l_oldEntry = l_nexus.read( l_oldDn ) ;
+ }
+ catch( BackendException e )
+ {
+ NamingException l_ne = new NamingException( "Failed entry rename "
+ + "on old name '" + l_oldDn + "' to new name of '"
+ + l_newDn + "' due to a nexus read failure." ) ;
+ l_ne.setRootCause( e ) ;
+ throw l_ne ;
+ }
+
+ // If both DNs are same size and their suffixes equal one another
+ // then this defaults to a simple modifyRdn operation.
+ if( l_oldDn.size() == l_newDn.size() )
+ {
+ try
+ {
+ l_nexus.modifyRdn( l_oldEntry, a_newRdn, true ) ;
+ }
+ catch( BackendException e )
+ {
+ NamingException l_ne = new NamingException( "Failed on nexus "
+ + "modifyRdn on old name '" + l_oldDn + "' to new name '"
+ + l_newDn + "' due to a backend failure." ) ;
+ l_ne.setRootCause( e ) ;
+ throw l_ne ;
+ }
+ }
+ // Here we are moving the entry down into a deeper level and need to
+ // determine if we are to change the rdn or not. If the first
+ // componenet of the oldName equals the first component of the newName
+ // then this is a simple move without an Rdn change.
+ else if( a_oldRdn.get( 0 ).equals( a_newRdn.get( 0 ) ) )
+ {
+ Name l_parentDn = l_newDn.getSuffix( 1 ) ;
+ LdapEntry l_parent = null ;
+
+ try
+ {
+ l_parent = l_nexus.read( l_parentDn ) ;
+ }
+ catch( BackendException e )
+ {
+ NamingException l_ne = new NamingException( "Failed rename "
+ + "on old name '" + l_oldDn + "' to new name of '"
+ + l_newDn + "' due to a nexus parent read error for a "
+ + "parent with name '" + l_parentDn + "'." ) ;
+ l_ne.setRootCause(e) ;
+ throw l_ne ;
+ }
+
+ try
+ {
+ l_nexus.move( l_parent, l_oldEntry ) ;
+ }
+ catch( BackendException e )
+ {
+ NamingException l_ne = new NamingException( "Failed on nexus "
+ + "move(" + l_parentDn + ", " + l_oldDn + ") due to a "
+ + "backend failure." ) ;
+ l_ne.setRootCause( e ) ;
+ throw l_ne ;
+ }
+
+ // Here we are doing a move and a Rdn change at the same time.
+ }
+ else
+ {
+ Name l_parentDn = l_newDn.getSuffix( 1 ) ;
+ LdapEntry l_parent = null ;
+
+ try
+ {
+ l_parent = l_nexus.read( l_parentDn ) ;
+ }
+ catch( BackendException e )
+ {
+ NamingException l_ne = new NamingException( "Failed rename "
+ + "on old name '" + l_oldDn + "' to new name of '"
+ + l_newDn + "' due to a nexus parent read error for a "
+ + "parent with name '" + l_parentDn + "'." ) ;
+ l_ne.setRootCause( e ) ;
+ throw l_ne ;
+ }
+
+ Name l_rdn = a_newRdn.getPrefix( 1 ) ;
+ try
+ {
+ l_nexus.move( l_parent, l_oldEntry, l_rdn, true ) ;
+ }
+ catch( BackendException e )
+ {
+ NamingException l_ne = new NamingException( "Failed on nexus "
+ + "move(" + l_parentDn + ", " + l_oldDn + ", " + l_rdn
+ + ", true) " + "due to a backend failure." ) ;
+ l_ne.setRootCause( e ) ;
+ throw l_ne ;
+ }
+ }
+ }
+
+
+ public void rename( String a_oldRdn, String a_newRdn )
+ throws NamingException
+ {
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ rename( l_nexus.getNormalizedName( a_oldRdn ),
+ l_nexus.getNormalizedName( a_newRdn ) ) ;
+ }
+
+
+ /**
+ * Destroys subcontexts by first building the distinguished name of the
+ * entry to destroy using the supplied relative distinguished name and
+ * the name of this node.
+ *
+ * @param a_rdn relative distinguished name describing a subordinate context
+ * to this one.
+ */
+ public void destroySubcontext( Name a_rdn )
+ throws NamingException
+ {
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ LdapEntry l_entry = m_ctx.getEntry() ;
+ LdapEntry l_oldEntry = null ;
+ Name l_dn = new LdapName() ;
+ l_dn.addAll( l_entry.getNormalizedDN() ) ;
+ l_dn.addAll( a_rdn ) ;
+
+ try
+ {
+ l_oldEntry = l_nexus.read( l_dn ) ;
+
+ // The exception here is equivalent to an
+ if( l_nexus.isSuffix( l_oldEntry ) )
+ {
+ StringBuffer l_buf = new StringBuffer() ;
+ l_buf.append( "[53] Entry with Dn '" ) ;
+ l_buf.append( l_dn.toString() ) ;
+ l_buf.append( "' is a suffix. Will not allow the deletion" ) ;
+ l_buf.append( " of a suffix entry! To remove suffix" ) ;
+ l_buf.append( " detach the backend from the server by" ) ;
+ l_buf.append( " removing the backend from the server's" ) ;
+ l_buf.append( " config.xml file." ) ;
+ String l_msg = l_buf.toString() ;
+ throw new OperationNotSupportedException( l_msg ) ;
+ }
+ }
+ catch( BackendException e )
+ {
+ NamingException l_ne = new NamingException( "Failed on nexus "
+ + "read(" + l_dn + ") due to a backend failure." ) ;
+ l_ne.setRootCause( e ) ;
+ throw l_ne ;
+ }
+
+ try
+ {
+ l_nexus.delete( l_oldEntry ) ;
+ }
+ catch( BackendException e )
+ {
+ NamingException l_ne = new NamingException( "Failed on nexus "
+ + "delete(" + l_dn + ") due to a backend failure." ) ;
+ l_ne.setRootCause( e ) ;
+ throw l_ne ;
+ }
+ }
+
+
+ public void destroySubcontext( String a_rdn ) throws NamingException
+ {
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ destroySubcontext( l_nexus.getNormalizedName( a_rdn ) ) ;
+ }
+
+
+ public Context createSubcontext( Name a_rdn )
+ throws NamingException
+ {
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ LdapEntry l_entry = m_ctx.getEntry() ;
+ LdapEntry l_oldEntry = null ;
+
+ // The argument name is really the name relative to this context so we
+ // need to build out the fully qualified name a.k.a. distinguished name
+ Name l_dn = new LdapName() ;
+ l_dn.addAll( l_entry.getUnNormalizedDN() ) ;
+ l_dn.addAll( a_rdn ) ;
+
+ try
+ {
+ l_oldEntry = l_nexus.newEntry( l_dn.toString() ) ;
+ }
+ catch( BackendException be )
+ {
+ NamingException l_ne = new NamingException( "Failed on nexus "
+ + "newEntry(" + l_dn + ") due to a backend failure." ) ;
+ l_ne.setRootCause( be ) ;
+ throw l_ne ;
+ }
+
+ String l_rdn = a_rdn.get( 0 ) ;
+ String l_rdnAttribute = NamespaceTools.getRdnAttribute( l_rdn ) ;
+ String l_rdnValue = NamespaceTools.getRdnValue( l_rdn ) ;
+ l_oldEntry.addValue( l_rdnAttribute, l_rdnValue ) ;
+ l_oldEntry.addValue( OBJECTCLASS_ATTR, JCONTAINER_ATTR ) ;
+ l_oldEntry.addValue( OBJECTCLASS_ATTR, TOP_ATTR ) ;
+
+ try
+ {
+ l_nexus.create( l_oldEntry ) ;
+ }
+ catch( BackendException be )
+ {
+ NamingException l_ne = new NamingException( "Failed on nexus "
+ + "create(" + l_dn + ") due to a backend failure on entry:\n"
+ + l_oldEntry ) ;
+ l_ne.setRootCause( be ) ;
+ throw l_ne ;
+ }
+
+ return new UnifiedLdapContext( m_ctx.getEnvironment(),
+ l_oldEntry ) ;
+ }
+
+
+ public Context createSubcontext( String a_rdn )
+ throws NamingException
+ {
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ return createSubcontext( l_nexus.getName( a_rdn ) ) ;
+ }
+
+
+ public NamingEnumeration list( Name a_rdn ) throws NamingException
+ {
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ LdapEntry l_entry = m_ctx.getEntry() ;
+ Cursor l_children = null ;
+ Name l_dn = new LdapName() ;
+ l_dn.addAll( l_entry.getNormalizedDN() ) ;
+ l_dn.addAll( a_rdn ) ;
+
+ try
+ {
+ l_children = l_nexus.listChildren( l_dn ) ;
+ }
+ catch( BackendException e )
+ {
+ NamingException l_ne = new NamingException( "Failed on nexus "
+ + "listChildren(" + l_dn + ") due to a backend failure." ) ;
+ l_ne.setRootCause( e ) ;
+ throw l_ne ;
+ }
+
+ return new NameClassPairEnumeration( l_nexus, l_children ) ;
+ }
+
+
+ public NamingEnumeration list(String a_rdn ) throws NamingException
+ {
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ return list( l_nexus.getNormalizedName( a_rdn ) ) ;
+ }
+
+
+ public NamingEnumeration listBindings( Name a_rdn ) throws NamingException
+ {
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ LdapEntry l_entry = m_ctx.getEntry() ;
+ Cursor l_children = null ;
+ Name l_dn = new LdapName() ;
+ l_dn.addAll( l_entry.getNormalizedDN() ) ;
+ l_dn.addAll( a_rdn ) ;
+
+ try
+ {
+ l_children = l_nexus.listChildren( l_dn ) ;
+ }
+ catch( BackendException e )
+ {
+ NamingException l_ne = new NamingException( "Failed on nexus "
+ + "listChildren("+l_dn+") due to a backend failure." ) ;
+ l_ne.setRootCause( e ) ;
+ throw l_ne ;
+ }
+
+ return new BindingEnumeration( m_ctx.getEnvironment(), l_children ) ;
+ }
+
+
+ public NamingEnumeration listBindings( String a_rdn ) throws NamingException
+ {
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ return listBindings( l_nexus.getNormalizedName( a_rdn ) ) ;
+ }
+
+
+ ////////////////////////////////////////////////
+ // Package Friendly & Private Utility Methods //
+ ////////////////////////////////////////////////
+
+
+ static Object deserialize( LdapEntry a_entry )
+ throws NamingException
+ {
+ ObjectInputStream l_in = null ;
+ String l_className = ( String )
+ a_entry.getSingleValue( JCLASSNAME_ATTR ) ;
+
+ try
+ {
+ byte [] l_data = ( byte [] )
+ a_entry.getSingleValue( JSERIALDATA_ATTR ) ;
+ l_in = new ObjectInputStream( new ByteArrayInputStream( l_data ) ) ;
+ Object l_obj = l_in.readObject() ;
+ return l_obj ;
+ }
+ catch( Exception e )
+ {
+ NamingException l_ne = new NamingException( "De-serialization of '"
+ + l_className + "' instance failed:\n" + e.getMessage() ) ;
+ l_ne.setRootCause( e ) ;
+ throw l_ne ;
+ }
+ finally
+ {
+ try
+ {
+ l_in.close() ;
+ }
+ catch( IOException e )
+ {
+ throw new NamingException(
+ "object deserialization stream close() failure" ) ;
+ }
+ }
+ }
+
+
+ static byte [] serialize( Object a_obj )
+ throws NamingException
+ {
+ ByteArrayOutputStream l_bytesOut = null ;
+ ObjectOutputStream l_out = null ;
+
+ try
+ {
+ l_bytesOut = new ByteArrayOutputStream() ;
+ l_out = new ObjectOutputStream( l_bytesOut ) ;
+ l_out.writeObject( a_obj ) ;
+ return l_bytesOut.toByteArray() ;
+ }
+ catch( Exception e )
+ {
+ NamingException l_ne = new NamingException( "Serialization of '"
+ + a_obj + "' failed:\n" + e.getMessage() ) ;
+ l_ne.setRootCause( e ) ;
+ throw l_ne ;
+ }
+ finally
+ {
+ try
+ {
+ l_out.close() ;
+ }
+ catch( IOException e )
+ {
+ throw new NamingException(
+ "object serialization stream close() failure" ) ;
+ }
+ }
+ }
+
+
+ static void populate( LdapEntry a_entry, Name a_rdn, Object a_obj )
+ throws NamingException
+ {
+ // Add the rdn attribute
+ a_entry.addValue(NamespaceTools.getRdnAttribute( a_rdn.get( 0 ) ),
+ NamespaceTools.getRdnValue( a_rdn.get( 0 ) ) ) ;
+
+ // Let's add the object classes first:
+ // objectClass: top
+ // objectClass: javaObject
+ // objectClass: javaContainer
+ // objectClass: javaSerializedObject
+ a_entry.addValue( OBJECTCLASS_ATTR, TOP_ATTR ) ;
+ a_entry.addValue( OBJECTCLASS_ATTR, JOBJECT_ATTR ) ;
+ a_entry.addValue( OBJECTCLASS_ATTR, JCONTAINER_ATTR ) ;
+ a_entry.addValue( OBJECTCLASS_ATTR, JSERIALIZEDOBJ_ATTR ) ;
+
+ // Add the javaClassName and javaSerializedData attributes
+ a_entry.addValue( JCLASSNAME_ATTR, a_obj.getClass().getName() ) ;
+ a_entry.addValue( JSERIALDATA_ATTR, serialize( a_obj ) ) ;
+
+ // Add all the class names this object can be cast to:
+ Class [] l_classes = a_obj.getClass().getClasses() ;
+ for( int ii = 0; ii < l_classes.length; ii++ )
+ {
+ a_entry.addValue( JCLASSNAMES_ATTR, l_classes[ii].getName() ) ;
+ }
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/jndi/DirContextHelper.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/jndi/DirContextHelper.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,773 @@
+/*
+ * $Id: DirContextHelper.java,v 1.5 2003/08/22 21:15:55 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.jndi ;
+
+
+import javax.naming.directory.DirContext;
+import org.apache.eve.backend.UnifiedBackend;
+import org.apache.eve.backend.LdapEntry;
+import javax.naming.NamingException;
+import javax.naming.directory.Attributes;
+import javax.naming.Name;
+import org.apache.ldap.common.name.LdapName;
+import org.apache.eve.backend.BackendException;
+import javax.naming.directory.BasicAttributes;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.BasicAttribute;
+import java.util.Collection;
+import java.util.Iterator;
+import javax.naming.directory.NoSuchAttributeException;
+import javax.naming.directory.ModificationItem;
+import javax.naming.NamingEnumeration;
+import java.util.HashSet;
+import javax.naming.directory.SearchControls;
+import org.apache.ldap.common.filter.ExprNode;
+import org.apache.ldap.common.filter.BranchNode;
+import org.apache.ldap.common.filter.PresenceNode;
+import java.util.ArrayList;
+import org.apache.ldap.common.filter.SimpleNode;
+import org.apache.eve.backend.Cursor;
+import org.apache.ldap.common.filter.FilterParser;
+import org.apache.ldap.common.filter.FilterParserImpl;
+import java.io.IOException;
+import java.text.ParseException;
+
+
+public class DirContextHelper
+{
+ private final UnifiedDirContext m_ctx ;
+
+
+ DirContextHelper( UnifiedDirContext a_dirCtx )
+ {
+ m_ctx = a_dirCtx ;
+ }
+
+
+ public Attributes getAttributes( Name a_rdn )
+ throws NamingException
+ {
+ return getAttributes( getEntry( a_rdn ), null ) ;
+ }
+
+
+ public Attributes getAttributes( String a_rdn )
+ throws NamingException
+ {
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ return getAttributes( getEntry( l_nexus.getNormalizedName( a_rdn ) ), null ) ;
+ }
+
+
+ public Attributes getAttributes(Name name, String[] attrIds)
+ throws NamingException
+ {
+ return getAttributes(getEntry(name), attrIds) ;
+ }
+
+
+ public Attributes getAttributes(String name, String[] attrIds)
+ throws NamingException
+ {
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ return getAttributes(l_nexus.getNormalizedName(name), attrIds) ;
+ }
+
+
+ public void modifyAttributes(Name name, int mod_op, Attributes attrs)
+ throws NamingException
+ {
+ LdapEntry l_entry = getEntry(name) ;
+ modify(l_entry, attrs, mod_op) ;
+ update(l_entry) ;
+ }
+
+
+ public void modifyAttributes(String name, int mod_op, Attributes attrs)
+ throws NamingException
+ {
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ modifyAttributes(l_nexus.getNormalizedName(name), mod_op, attrs) ;
+ }
+
+
+ public void modifyAttributes( Name name, ModificationItem[] mods )
+ throws NamingException
+ {
+ LdapEntry l_entry = getEntry(name) ;
+
+ for(int ii = 0; ii < mods.length; ii++) {
+ ModificationItem l_mod = mods[ii] ;
+ switch(l_mod.getModificationOp()) {
+ case(DirContext.ADD_ATTRIBUTE):
+ add(l_entry, l_mod.getAttribute()) ;
+ break ;
+ case(DirContext.REMOVE_ATTRIBUTE):
+ remove(l_entry, l_mod.getAttribute()) ;
+ break ;
+ case(DirContext.REPLACE_ATTRIBUTE):
+ replace(l_entry, l_mod.getAttribute()) ;
+ break ;
+ default:
+ throw new NamingException("Unidentified modification "
+ + "operation: " + l_mod.getModificationOp()) ;
+ }
+ }
+
+ update(l_entry) ;
+ }
+
+
+ public void modifyAttributes(String name, ModificationItem[] mods)
+ throws NamingException
+ {
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ modifyAttributes(l_nexus.getNormalizedName(name), mods) ;
+ }
+
+
+ public void bind(Name name, Object obj, Attributes attrs)
+ throws NamingException
+ {
+ LdapEntry l_entry = null ;
+
+ if(null == obj && null == attrs) {
+ throw new NamingException("Both the obj and attrs args were null. "
+ + "At least one of these parameters must not be null.") ;
+ }
+
+ l_entry = newEntry(name) ;
+ if(obj != null) {
+ l_entry = getEntry(name) ;
+ ContextHelper.populate(l_entry, name, obj) ;
+ }
+
+ if(attrs != null) {
+ modify(l_entry, attrs, DirContext.ADD_ATTRIBUTE) ;
+ }
+
+ create(l_entry) ;
+ }
+
+
+ public void bind(String name, Object obj, Attributes attrs)
+ throws NamingException
+ {
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ bind(l_nexus.getNormalizedName(name), obj, attrs) ;
+ }
+
+
+ public void rebind(Name name, Object obj, Attributes attrs)
+ throws NamingException
+ {
+ if(hasEntry(name)) {
+ m_ctx.unbind(name) ;
+ }
+
+ bind(name, obj, attrs) ;
+ }
+
+
+ public void rebind(String name, Object obj, Attributes attrs)
+ throws NamingException
+ {
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ rebind(l_nexus.getNormalizedName(name), obj, attrs) ;
+ }
+
+
+ public DirContext createSubcontext( Name a_name, Attributes a_attrs )
+ throws NamingException
+ {
+ LdapEntry l_entry = null ;
+
+ if( null == a_attrs )
+ {
+ m_ctx.createSubcontext( a_name ) ;
+ }
+
+ l_entry = newEntry( a_name ) ;
+ modify( l_entry, a_attrs, DirContext.ADD_ATTRIBUTE ) ;
+ create( l_entry ) ;
+ return new
+ UnifiedLdapContext( m_ctx.getEnvironment(), l_entry ) ;
+ }
+
+
+ public DirContext createSubcontext( String a_name, Attributes a_attrs )
+ throws NamingException
+ {
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ return createSubcontext( l_nexus.getName( a_name ), a_attrs) ;
+ }
+
+
+ ///////////////////////////////////
+ // Search Method Implementations //
+ ///////////////////////////////////
+
+
+ /**
+ * Single level scope search using this helper's context as the base DN.
+ * It uses the default search controls specified by the default
+ * SearchControls constructor.
+ */
+ public NamingEnumeration search(Name name,
+ Attributes matchingAttributes,
+ String[] attributesToReturn)
+ throws NamingException
+ {
+ Cursor l_cursor = null ;
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+
+ // If matchingAttributes is null or empty then all children under this
+ // context are returned.
+ if(null == matchingAttributes || matchingAttributes.size() == 0) {
+ l_cursor = listChildren(name) ;
+ } else {
+ l_cursor = search(getExprNode(matchingAttributes), name,
+ SearchControls.ONELEVEL_SCOPE) ;
+ }
+
+ return new SearchResultEnumeration(m_ctx, l_nexus, l_cursor,
+ attributesToReturn, new SearchControls()) ;
+ }
+
+
+ public NamingEnumeration search(String name,
+ Attributes matchingAttributes,
+ String[] attributesToReturn)
+ throws NamingException
+ {
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ return search(l_nexus.getName(name), matchingAttributes,
+ attributesToReturn) ;
+ }
+
+
+ public NamingEnumeration search(Name name,
+ Attributes matchingAttributes)
+ throws NamingException
+ {
+ return search(name, matchingAttributes, null) ;
+ }
+
+
+ public NamingEnumeration search(String name,
+ Attributes matchingAttributes)
+ throws NamingException
+ {
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ return search(l_nexus.getName(name), matchingAttributes, null) ;
+ }
+
+
+ public NamingEnumeration search(Name name,
+ String filter,
+ SearchControls cons)
+ throws NamingException
+ {
+ Cursor l_cursor = search(getExprNode(filter), name,
+ cons.getSearchScope()) ;
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ return new SearchResultEnumeration(m_ctx, l_nexus, l_cursor,
+ null, cons) ;
+ }
+
+
+ public NamingEnumeration search(String name,
+ String filter,
+ SearchControls cons)
+ throws NamingException
+ {
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ return search(l_nexus.getName(name), filter, cons) ;
+ }
+
+
+ public NamingEnumeration search(Name name,
+ String filterExpr,
+ Object[] filterArgs,
+ SearchControls cons)
+ throws NamingException
+ {
+ Cursor l_cursor = search(getExprNode(filterExpr, filterArgs), name,
+ cons.getSearchScope()) ;
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ return new SearchResultEnumeration(m_ctx, l_nexus, l_cursor,
+ null, cons) ;
+ }
+
+
+ public NamingEnumeration search(String name,
+ String filterExpr,
+ Object[] filterArgs,
+ SearchControls cons)
+ throws NamingException
+ {
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ return search(l_nexus.getName(name), filterExpr, filterArgs, cons) ;
+ }
+
+
+ ////////////////////////////////////////////
+ // Private & Pkg Friendly Utility Methods //
+ ////////////////////////////////////////////
+
+
+ /**
+ * Adds attributes to an LdapEntry.
+ *
+ * @param a_entry the entry to add the attributes to
+ * @param a_attribute the set of attributes and their values to add.
+ */
+ static void add( LdapEntry a_entry, Attribute a_attribute )
+ throws NamingException
+ {
+ NamingEnumeration l_list = a_attribute.getAll() ;
+
+ while( l_list.hasMore() )
+ {
+ a_entry.addValue( a_attribute.getID(), l_list.next() ) ;
+ }
+ }
+
+
+ /**
+ * Removes values from the entry which are specified in the Attribute. When
+ * the Attribute argument has no entries this method interprets the call to
+ * mean remove all values associated with the id of a_attribute for complete
+ * remove. If there are some values associated with a_attribute then only
+ * those values are removed in a partial manner.
+ *
+ * @param a_entry the LdapEntry to remove the values or attribute from
+ * @param a_attribute the attribute and/or its values to remove.
+ */
+ static void remove( LdapEntry a_entry, Attribute a_attribute )
+ throws NamingException
+ {
+ NamingEnumeration l_list = a_attribute.getAll() ;
+
+ // If a_attributes does have value then we only remove those values and
+ // not all of the values associated with the id of the attribute so this
+ // is a partial remove scenario
+ if( l_list.hasMore() )
+ {
+ while( l_list.hasMore() )
+ {
+ a_entry.removeValue( a_attribute.getID(), l_list.next() ) ;
+ }
+ }
+ // Here all values associated with the attribute are removed.
+ else
+ {
+ a_entry.removeValues( a_attribute.getID() ) ;
+ }
+ }
+
+
+ static void replace( LdapEntry a_entry, Attribute a_attribute )
+ throws NamingException
+ {
+ // Clear all values here for the attribute to replace.
+ a_entry.removeValues( a_attribute.getID() ) ;
+
+ // Now add all the new values for this attribute.
+ NamingEnumeration l_list = a_attribute.getAll() ;
+ while( l_list.hasMore() )
+ {
+ a_entry.addValue( a_attribute.getID(), l_list.next() ) ;
+ }
+ }
+
+
+ /**
+ * Modifies an entry according to a modification type using the attributes
+ * specified within an Attributes parameter.
+ *
+ * @param a_entry the LdapEntry to modify
+ * @param a_attributes the set of attributes and values to use in the
+ * modification
+ * @param a_modOp the modification type/operation to perform
+ */
+ static void modify( LdapEntry a_entry, Attributes a_attributes,
+ int a_modOp )
+ throws NamingException
+ {
+ NamingEnumeration l_list = a_attributes.getAll() ;
+
+ while( l_list.hasMore() )
+ {
+ Attribute l_attr = ( Attribute ) l_list.next() ;
+
+ switch( a_modOp )
+ {
+ case( DirContext.ADD_ATTRIBUTE ):
+ add( a_entry, l_attr ) ;
+ break ;
+ case( DirContext.REMOVE_ATTRIBUTE ):
+ remove( a_entry, l_attr ) ;
+ break ;
+ case( DirContext.REPLACE_ATTRIBUTE ):
+ replace( a_entry, l_attr ) ;
+ break ;
+ default:
+ // We put this exception into the OTHER category since the code
+ // catches the problem and is not an OPERATIONSERROR.
+ throw new NamingException(
+ "[80] Unidentified modification operation: " + a_modOp ) ;
+ }
+ }
+ }
+
+
+ void update( LdapEntry a_entry )
+ throws NamingException
+ {
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+
+ try
+ {
+ l_nexus.update( a_entry ) ;
+ }
+ catch( BackendException be )
+ {
+ NamingException l_ne = new NamingException(
+ "Failed on entry update for '" + a_entry.getEntryDN() + "'." ) ;
+ l_ne.setRootCause( be ) ;
+ throw l_ne ;
+ }
+ }
+
+
+ void create( LdapEntry a_entry )
+ throws NamingException
+ {
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+
+ try
+ {
+ l_nexus.create( a_entry ) ;
+ }
+ catch( BackendException be )
+ {
+ NamingException l_ne = new NamingException(
+ "Failed on entry create for '" + a_entry.getEntryDN() + "'." ) ;
+ l_ne.setRootCause( be ) ;
+ throw l_ne ;
+ }
+ }
+
+
+ void delete( LdapEntry a_entry )
+ throws NamingException
+ {
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+
+ try
+ {
+ l_nexus.delete( a_entry ) ;
+ }
+ catch( BackendException be )
+ {
+ NamingException l_ne = new NamingException(
+ "Failed on entry delete for '" + a_entry.getEntryDN() + "'." ) ;
+ l_ne.setRootCause( be ) ;
+ throw l_ne ;
+ }
+ }
+
+
+ /**
+ * Utility method to create a new invalid entry that is not yet created in
+ * the backend.
+ *
+ * @param a_name the non-normalized relative dn of the new entry to
+ */
+ LdapEntry newEntry( Name a_name )
+ throws NamingException
+ {
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ LdapEntry l_entry = m_ctx.getEntry() ;
+ Name l_dn = new LdapName() ;
+ l_dn.addAll( l_entry.getUnNormalizedDN() ) ;
+ l_dn.addAll( a_name ) ;
+
+ try
+ {
+ return l_nexus.newEntry( l_dn.toString() ) ;
+ }
+ catch( BackendException be )
+ {
+ NamingException l_ne = new NamingException( "Failed on newEntry( "
+ + l_dn + " ) due to backend failure." ) ;
+ l_ne.setRootCause( be ) ;
+ throw l_ne ;
+ }
+ }
+
+
+ /**
+ * Gets an LdapEntry from the appropriate DIB off the nexus using a name
+ * relative to the entry associated with the DirContext of this helper.
+ */
+ LdapEntry getEntry( Name a_rdn )
+ throws NamingException
+ {
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ LdapEntry l_entry = m_ctx.getEntry() ;
+ Name l_dn = new LdapName() ;
+ l_dn.addAll( l_nexus.getName( l_entry.getEntryDN() ) ) ;
+ l_dn.addAll( a_rdn ) ;
+
+ try
+ {
+ return l_nexus.read( l_dn ) ;
+ }
+ catch( BackendException be )
+ {
+ NamingException l_ne = new NamingException( "Failed on entry read "
+ + "for '" + l_dn + "'." ) ;
+ l_ne.setRootCause( be ) ;
+ throw l_ne ;
+ }
+ }
+
+
+ /**
+ * Checks for a entry from the appropriate DIB off the nexus using a name
+ * relative to the entry associated with the DirContext of this helper.
+ */
+ boolean hasEntry( Name a_rdn )
+ throws NamingException
+ {
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ LdapEntry l_entry = m_ctx.getEntry() ;
+ Name l_dn = new LdapName() ;
+ l_dn.addAll( l_entry.getNormalizedDN() ) ;
+ l_dn.addAll( a_rdn ) ;
+
+ try
+ {
+ return l_nexus.hasEntry( l_dn ) ;
+ }
+ catch( BackendException be )
+ {
+ NamingException l_ne = new NamingException( "Failed on hasEntry "
+ + "for '" + l_dn + "'." ) ;
+ l_ne.setRootCause( be ) ;
+ throw l_ne ;
+ }
+ }
+
+
+ Cursor listChildren( Name a_rdn )
+ throws NamingException
+ {
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ LdapEntry l_entry = m_ctx.getEntry() ;
+ Name l_dn = new LdapName() ;
+ l_dn.addAll( l_entry.getNormalizedDN() ) ;
+ l_dn.addAll( a_rdn ) ;
+
+ try
+ {
+ return l_nexus.listChildren( l_dn ) ;
+ }
+ catch( BackendException be )
+ {
+ NamingException l_ne = new NamingException(
+ "Failed on listChildren for '" + l_dn + "'." ) ;
+ l_ne.setRootCause( be ) ;
+ throw l_ne ;
+ }
+ }
+
+
+ Cursor search(ExprNode a_filter, Name a_rn, int a_scope)
+ throws NamingException
+ {
+ UnifiedBackend l_nexus = JndiProviderModule.getInstance().getNexus() ;
+ LdapEntry l_entry = m_ctx.getEntry() ;
+ Name l_dn = new LdapName() ;
+ l_dn.addAll( l_entry.getNormalizedDN() ) ;
+ l_dn.addAll( a_rn ) ;
+
+ try {
+ return l_nexus.search(a_filter, l_dn, a_scope) ;
+ } catch(BackendException e) {
+ NamingException l_ne = new NamingException("Failed on search "
+ + "for '" + l_dn + "'.") ;
+ l_ne.setRootCause(e) ;
+ throw l_ne ;
+ }
+ }
+
+
+ /**
+ * @return attribute in a_entry for an attribute identitifier if the
+ * attribute exists.
+ * @throws NoSuchAttributeException if a_entry does not contain the
+ * requested attribute.
+ */
+ static Attribute getAttribute(LdapEntry a_entry, String a_attribName)
+ throws NoSuchAttributeException
+ {
+ BasicAttribute l_attrib = new BasicAttribute(a_attribName) ;
+ Collection l_values = (Collection) a_entry.getMultiValue(a_attribName) ;
+
+ // SCREAM if attribute does not exist.
+ if(null == l_values) {
+ throw new NoSuchAttributeException("Attribute " + a_attribName
+ + " does not exist within entry '"
+ + a_entry.getEntryDN() + "'") ;
+ }
+
+ Iterator l_list = l_values.iterator() ;
+ while(l_list.hasNext()) {
+ l_attrib.add(l_list.next()) ;
+ }
+
+ return l_attrib ;
+ }
+
+
+ /**
+ * Generates the set of attributes for an entry using a specified attribute
+ * list to select for specific attributes. If the attribute list array is
+ * null all attributes are packaged and returned.
+ */
+ static Attributes getAttributes(LdapEntry a_entry, String [] attribList)
+ throws NamingException
+ {
+ // Don't need this bullshit of the entry does it for us already.
+ HashSet l_lut = null ;
+
+ // Optionally create fast normalized lookup table for attribute ids
+ if(attribList != null) {
+ // Hash lowercased versions of attributes so we do not generate strs
+ // over and over again while searching through attribute list.
+ l_lut = new HashSet(attribList.length) ;
+ for(int ii = 0; ii < attribList.length; ii++) {
+ String l_lower = attribList[ii].toLowerCase() ;
+ l_lut.add(l_lower) ;
+ }
+ }
+
+ // Iterate through list of attributes and add them to the new Attributes
+ // instance based on the attribute list array if it was not null
+ // otherwise we return all attributes.
+ BasicAttributes l_attributes = new BasicAttributes(true) ;
+ Iterator l_list = a_entry.attributes().iterator() ;
+ while(l_list.hasNext()) {
+ String l_attribName = (String) l_list.next() ;
+
+ // If l_lut exists we add the attribute only if it is in the lut
+ if(l_lut != null && l_lut.contains(l_attribName.toLowerCase())) {
+ l_attributes.put(getAttribute(a_entry, l_attribName)) ;
+ // Lut is null so we add all attributes.
+ } else if(null == l_lut) {
+ l_attributes.put(getAttribute(a_entry, l_attribName)) ;
+ }
+
+ // If lut is not null but the attribute name is not present in
+ // it as a key then we do not include the attribute in the response.
+ }
+
+ return l_attributes ;
+ }
+
+
+ /**
+ * Builds an expression tree that matches for a set of attribute value
+ * pairs under one AND expression. If an attribute does not have any
+ * values then it is a presence assertion node. Otherwise the attributes
+ * values are used in as many equality expressions as there are values using
+ * that attributes identifier.
+ */
+ ExprNode getExprNode(Attributes l_attributes)
+ throws NamingException
+ {
+ ArrayList l_nodes = new ArrayList() ;
+ NamingEnumeration l_attrList = l_attributes.getAll() ;
+ while(l_attrList.hasMore()) {
+ Attribute l_attr = (Attribute) l_attrList.next() ;
+
+ if(l_attr.size() == 0) {
+ l_nodes.add(new PresenceNode(l_attr.getID())) ;
+ } else {
+ NamingEnumeration l_values = l_attr.getAll() ;
+ while(l_values.hasMore()) {
+ String l_val = (String) l_values.next() ;
+ l_nodes.add(new SimpleNode(l_attr.getID(), l_val,
+ SimpleNode.EQUALITY)) ;
+ }
+ }
+ }
+
+ return new BranchNode(BranchNode.AND, l_nodes) ;
+ }
+
+
+ static FilterParser s_parser = null ;
+ ExprNode getExprNode(String a_filter)
+ throws NamingException
+ {
+ if(null == s_parser) {
+ try {
+ s_parser = new FilterParserImpl() ;
+ } catch(IOException e) {
+ NamingException l_ne = new NamingException("Failed on "
+ + "FilterParser init.") ;
+ l_ne.setRootCause(e) ;
+ throw l_ne ;
+ }
+ }
+
+ try {
+ return s_parser.parse(a_filter) ;
+ } catch(ParseException e) {
+ NamingException l_ne = new NamingException("Failed on "
+ + "FilterParser parse of filter:\n'" + a_filter + "'") ;
+ l_ne.setRootCause(e) ;
+ throw l_ne ;
+ } catch(IOException e) {
+ NamingException l_ne = new NamingException("Failed on "
+ + "FilterParser parse of filter:\n'" + a_filter + "'") ;
+ l_ne.setRootCause(e) ;
+ throw l_ne ;
+ }
+ }
+
+
+ ExprNode getExprNode(String a_filter, Object [] a_filterArgs)
+ throws NamingException
+ {
+ StringBuffer l_buf = new StringBuffer() ;
+ StringBuffer l_tmp = new StringBuffer() ;
+ for(int ii = 0 ; ii < a_filter.length() ; ii++) {
+ if(a_filter.charAt(ii) == '{') {
+ ii++ ;
+ while(a_filter.charAt(ii) != '}') {
+ l_tmp.append(a_filter.charAt(ii)) ;
+ ii++ ;
+ }
+
+ int l_arg = Integer.parseInt(l_tmp.toString()) ;
+ l_buf.append(a_filterArgs[l_arg].toString()) ;
+ } else {
+ l_buf.append(a_filter.charAt(ii)) ;
+ }
+ }
+
+ return getExprNode(l_buf.toString()) ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/jndi/JndiProvider.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/jndi/JndiProvider.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,25 @@
+/*
+ * $Id: JndiProvider.java,v 1.3 2003/03/13 18:27:32 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.jndi ;
+
+
+import java.util.Hashtable ;
+
+import javax.naming.NamingException ;
+import javax.naming.ldap.LdapContext ;
+
+
+public interface JndiProvider
+{
+ public static final String ROLE = JndiProvider.class.getName() ;
+
+ LdapContext getContext(Hashtable an_environment)
+ throws NamingException ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/jndi/JndiProviderModule.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/jndi/JndiProviderModule.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,190 @@
+/*
+ * $Id: JndiProviderModule.java,v 1.7 2003/08/22 21:15:55 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.jndi ;
+
+
+import java.util.Hashtable ;
+
+import javax.naming.Context ;
+import javax.naming.NamingException ;
+import javax.naming.ldap.LdapContext ;
+
+import org.apache.eve.AbstractModule ;
+import org.apache.eve.backend.UnifiedBackend ;
+
+import org.apache.avalon.framework.service.ServiceManager ;
+import org.apache.avalon.framework.service.ServiceException ;
+import org.apache.avalon.framework.configuration.Configuration ;
+import org.apache.eve.client.ClientManager;
+
+
+/**
+ * Protocol engine stage: the request processing stage of the pipeline.
+ *
+ * @phoenix:block
+ * @phoenix:service name="org.apache.eve.jndi.JndiProvider"
+ * @phoenix:mx-topic name="JndiProviderModule"
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.7 $
+ */
+public class JndiProviderModule
+ extends AbstractModule
+ implements JndiProvider
+{
+ private static JndiProviderModule s_singleton = null ;
+ private UnifiedBackend m_nexus = null ;
+ private ClientManager m_clientManager = null ;
+
+
+ // ------------------------------------------------------------------------
+ // Constructor
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Creates a singlton instance of the JndiProvider for the entire JVM.
+ * Multiple calls to this method will raise an exception.
+ *
+ * @throws IllegalStateException if another JndiProvider has already been
+ * initialized.
+ */
+ public JndiProviderModule()
+ {
+ if( s_singleton != null )
+ {
+ throw new IllegalStateException(
+ "Cannot instantiate more than one Server-Side JndiProvider!" ) ;
+ }
+
+ s_singleton = this ;
+ }
+
+
+ static JndiProviderModule getInstance()
+ {
+ if( null == s_singleton )
+ {
+ throw new IllegalStateException(
+ "Cannot return singleton instance without initialization!" ) ;
+ }
+
+ return s_singleton ;
+ }
+
+
+ /**
+ * Creates a default context at the root DSE.
+ */
+ public LdapContext getContext( Hashtable an_environment )
+ throws NamingException
+ {
+ return new UnifiedLdapContext( an_environment ) ;
+ }
+
+
+
+ // ------------------------------------------------------------------------
+ // Avalon Lifecycle Methods & Other Module Interface Method Implementations
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Gets a descriptive String for this JndiProvider implementation.
+ *
+ * @phoenix:mx-attribute
+ * @phoenix:mx-description Returns the implementation name.
+ * @phoenix:mx-isWriteable no
+ */
+ public String getImplementationName()
+ {
+ return "Server-Side JNDI Provider Module" ;
+ }
+
+
+ /**
+ * Gets the ROLE or fully qualified class name of the service interface
+ * associated with this implementation.
+ *
+ * @phoenix:mx-attribute
+ * @phoenix:mx-description Returns the implementation role.
+ * @phoenix:mx-isWriteable no
+ */
+ public String getImplementationRole()
+ {
+ return ROLE ;
+ }
+
+
+ /**
+ * Gets the fully qualified class name implementation class.
+ *
+ * @phoenix:mx-attribute
+ * @phoenix:mx-description Returns the implementation class name.
+ * @phoenix:mx-isWriteable no
+ */
+ public String getImplementationClassName()
+ {
+ return this.getClass().getName() ;
+ }
+
+
+ public void configure( Configuration a_config )
+ {
+ // Does nothing for now.
+ }
+
+
+ /**
+ * Gets a handle on the UnifiedBackend service aka NexusModule.
+ *
+ * @phoenix:dependency name="org.apache.eve.backend.UnifiedBackend"
+ */
+ public void service( ServiceManager a_manager )
+ throws ServiceException
+ {
+ m_nexus = ( UnifiedBackend ) a_manager.lookup( UnifiedBackend.ROLE ) ;
+ }
+
+
+ public void stop()
+ {
+ s_singleton = null ;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // Package friendly methods used by contexts and their helpers
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Gets the ClientManager this ClientManagerSlave subordinates to.
+ *
+ * @return the ClientManager master
+ */
+ ClientManager getClientManager()
+ {
+ return m_clientManager ;
+ }
+
+
+ /**
+ * Gets a handle on the UnifiedBackend this module and its Contexts and
+ * helpers need to perform operations against backends.
+ *
+ * @return a handle on the backend nexus
+ */
+ UnifiedBackend getNexus()
+ {
+ return m_nexus ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/jndi/NameClassPairEnumeration.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/jndi/NameClassPairEnumeration.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,99 @@
+/*
+ * $Id: NameClassPairEnumeration.java,v 1.3 2003/03/13 18:27:33 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.jndi ;
+import javax.naming.NamingEnumeration;
+import org.apache.eve.backend.Cursor;
+import javax.naming.NamingException;
+import org.apache.eve.backend.LdapEntry;
+import javax.naming.NameClassPair;
+import org.apache.eve.backend.UnifiedBackend;
+import java.util.Hashtable;
+import org.apache.avalon.framework.ExceptionUtil;
+
+
+public class NameClassPairEnumeration
+ implements NamingEnumeration
+{
+ private final Cursor m_cursor ;
+ private final UnifiedBackend m_nexus ;
+
+
+ NameClassPairEnumeration(UnifiedBackend a_nexus, Cursor a_cursor)
+ {
+ m_nexus = a_nexus ;
+ m_cursor = a_cursor ;
+ }
+
+
+ public void close()
+ throws NamingException
+ {
+ m_cursor.close() ;
+ }
+
+
+ public boolean hasMore()
+ throws NamingException
+ {
+ return m_cursor.hasMore() ;
+ }
+
+
+ public Object next()
+ throws NamingException
+ {
+ String l_rdn = null ;
+ String l_class = null ;
+
+ LdapEntry l_entry = (LdapEntry) m_cursor.next() ;
+ if(l_entry.hasAttribute(ContextHelper.JCLASSNAME_ATTR)) {
+ l_class = (String)
+ l_entry.getSingleValue(ContextHelper.JCLASSNAME_ATTR) ;
+ } else {
+ l_class = UnifiedLdapContext.class.getName() ;
+ }
+
+ l_rdn = m_nexus.getNormalizedName(l_entry.getEntryDN()).get(0) ;
+ return new NameClassPair(l_rdn, l_class) ;
+ }
+
+
+ public boolean hasMoreElements()
+ {
+ return m_cursor.hasMoreElements() ;
+ }
+
+
+ public Object nextElement()
+ {
+ String l_rdn = null ;
+ String l_class = null ;
+
+ LdapEntry l_entry = (LdapEntry) m_cursor.nextElement() ;
+ if(l_entry.hasAttribute(ContextHelper.JCLASSNAME_ATTR)) {
+ l_class = (String)
+ l_entry.getSingleValue(ContextHelper.JCLASSNAME_ATTR) ;
+ } else {
+ l_class = UnifiedLdapContext.class.getName() ;
+ }
+
+ try {
+ l_rdn = m_nexus.getNormalizedName(l_entry.getEntryDN()).get(0) ;
+ } catch(NamingException e) {
+ try {
+ m_cursor.close() ;
+ } catch(Exception e2) { }
+ throw new java.util.NoSuchElementException("Premature close of "
+ + "backend cursor:\n" + ExceptionUtil.printStackTrace(e)) ;
+ }
+
+ return new NameClassPair(l_rdn, l_class) ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/jndi/SearchResultEnumeration.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/jndi/SearchResultEnumeration.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,138 @@
+/*
+ * $Id: SearchResultEnumeration.java,v 1.3 2003/08/22 21:15:55 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.jndi ;
+
+
+import java.util.HashMap ;
+
+import javax.naming.NamingEnumeration ;
+
+import org.apache.eve.backend.Cursor ;
+import javax.naming.directory.SearchResult ;
+import org.apache.eve.backend.LdapEntry ;
+import java.util.Iterator;
+import javax.naming.directory.BasicAttributes ;
+import javax.naming.directory.DirContext ;
+import javax.naming.Name ;
+import org.apache.eve.backend.UnifiedBackend ;
+import java.util.Collections ;
+import javax.naming.NamingException ;
+import org.apache.avalon.framework.ExceptionUtil ;
+import javax.naming.directory.SearchControls ;
+
+
+
+public class SearchResultEnumeration
+ implements NamingEnumeration
+{
+ private final String [] m_attribsToReturn ;
+ private final UnifiedBackend m_nexus ;
+ private final DirContext m_context ;
+ private final Cursor m_cursor ;
+ private final SearchControls m_ctls ;
+
+
+ SearchResultEnumeration(DirContext a_context,
+ UnifiedBackend a_nexus, Cursor a_cursor, SearchControls a_ctls)
+ {
+ this(a_context, a_nexus, a_cursor, null, a_ctls) ;
+ }
+
+
+ SearchResultEnumeration(DirContext a_context, UnifiedBackend a_nexus,
+ Cursor a_cursor, String [] a_attribsToReturn, SearchControls a_ctls)
+ {
+ m_ctls = a_ctls ;
+ m_nexus = a_nexus ;
+ m_cursor = a_cursor ;
+ m_context = a_context ;
+
+ if(a_attribsToReturn != null && a_attribsToReturn.length > 0) {
+ m_attribsToReturn = a_attribsToReturn ;
+ } else {
+ m_attribsToReturn = m_ctls.getReturningAttributes() ;
+ }
+ }
+
+
+ SearchResult getResult(LdapEntry a_entry)
+ throws NamingException
+ {
+ Object l_obj = null ;
+ BasicAttributes l_attribs = new BasicAttributes(true) ;
+
+ if(null == m_attribsToReturn) {
+ Iterator l_list = a_entry.attributes().iterator() ;
+ while(l_list.hasNext()) {
+ l_attribs.put(DirContextHelper.getAttribute(a_entry,
+ (String) l_list.next())) ;
+ }
+ } else {
+ for(int ii = 0; ii < m_attribsToReturn.length; ii++) {
+ l_attribs.put(DirContextHelper.getAttribute(a_entry,
+ m_attribsToReturn[ii])) ;
+ }
+ }
+
+ if(a_entry.hasAttribute(ContextHelper.JCLASSNAME_ATTR)) {
+ l_obj = ContextHelper.deserialize(a_entry) ;
+ } else {
+ l_obj = new UnifiedLdapContext( m_context.getEnvironment(),
+ a_entry ) ;
+ }
+
+ return new SearchResult(a_entry.getEntryDN(), l_obj, l_attribs, false) ;
+ }
+
+
+ public boolean hasMore()
+ throws NamingException
+ {
+ return m_cursor.hasMore() ;
+ }
+
+
+ public boolean hasMoreElements()
+ {
+ try {
+ return hasMore() ;
+ } catch(NamingException e) {
+ throw new java.util.NoSuchElementException("Could not get next "
+ + " element due to underlying exception:\n"
+ + ExceptionUtil.printStackTrace(e)) ;
+ }
+ }
+
+
+ public Object next()
+ throws NamingException
+ {
+ return getResult((LdapEntry) m_cursor.next()) ;
+ }
+
+
+ public Object nextElement()
+ {
+ try {
+ return next() ;
+ } catch(NamingException e) {
+ throw new java.util.NoSuchElementException("Could not get next "
+ + " element due to underlying exception:\n"
+ + ExceptionUtil.printStackTrace(e)) ;
+ }
+ }
+
+
+ public void close()
+ throws NamingException
+ {
+ m_cursor.close() ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/jndi/ServerContextFactory.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/jndi/ServerContextFactory.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,28 @@
+/*
+ * $Id: ServerContextFactory.java,v 1.3 2003/08/22 21:15:55 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.jndi ;
+
+
+import java.util.Hashtable ;
+
+import javax.naming.Context ;
+import javax.naming.NamingException ;
+
+
+public class ServerContextFactory
+ implements javax.naming.spi.InitialContextFactory
+{
+ public Context getInitialContext( Hashtable an_envoronment )
+ throws NamingException
+ {
+ JndiProviderModule l_module = JndiProviderModule.getInstance() ;
+ return l_module.getContext( an_envoronment ) ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/jndi/UnifiedContext.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/jndi/UnifiedContext.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,840 @@
+/*
+ * $Id: UnifiedContext.java,v 1.7 2003/08/22 21:15:55 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.jndi ;
+
+
+import java.util.Hashtable ;
+
+import javax.naming.Name ;
+import javax.naming.Context ;
+import javax.naming.NameParser ;
+import javax.naming.NamingException ;
+import javax.naming.ldap.LdapContext ;
+import javax.naming.NamingEnumeration ;
+
+import org.apache.ldap.common.name.LdapName ;
+import org.apache.eve.backend.LdapEntry ;
+import org.apache.eve.client.ClientManager ;
+import org.apache.eve.backend.UnifiedBackend ;
+
+
+/**
+ * Base Context method implementations are placed here. The ContextHelper is
+ * used to contain methods larger than a few lines. In general because the
+ * Context interface is so huge, we try to relocate functionality to the
+ * context helper where we can.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.7 $
+ */
+public abstract class UnifiedContext
+ implements Context
+{
+ /** The relative distinguished name represented by this context */
+ protected final Name m_rdn ;
+ /** The environment for this context */
+ protected final Hashtable m_env ;
+ /** The entry this context represents */
+ protected final LdapEntry m_entry ;
+ /** The helper used by this context */
+ protected final ContextHelper m_helper ;
+
+
+ /**
+ * Creates the default context pointing to the RootDSE using the empty DN.
+ *
+ * @param an_environment the environment setting for the context
+ */
+ protected UnifiedContext( Hashtable an_environment )
+ {
+ m_env = ( Hashtable ) an_environment.clone() ;
+ m_rdn = new LdapName() ;
+
+ JndiProviderModule l_provider = JndiProviderModule.getInstance() ;
+ UnifiedBackend l_nexus = l_provider.getNexus() ;
+ m_entry = l_nexus.getRootDSE() ;
+ m_helper = new ContextHelper( this ) ;
+ }
+
+
+ /**
+ * Creates a context around an LdapEntry at a specific point in the DIT.
+ *
+ * @param an_environment the environment setting for the context
+ * @param a_entry the entry this context represents
+ */
+ protected UnifiedContext( Hashtable an_environment, LdapEntry a_entry )
+ throws NamingException
+ {
+ m_env = ( Hashtable ) an_environment.clone() ;
+
+ // Set rdn to the first Name component of unnormalized Dn of the entry
+ m_rdn = new LdapName() ;
+ Name l_dn = a_entry.getUnNormalizedDN() ;
+ m_rdn.add( l_dn.get( 0 ) ) ;
+
+ m_entry = a_entry ;
+ m_helper = new ContextHelper( this ) ;
+ }
+
+
+ /////////////////////////////
+ // Context Implementations //
+ /////////////////////////////
+
+
+ /**
+ * Retrieves the named object.
+ * If <tt>name</tt> is empty, returns a new instance of this context
+ * (which represents the same naming context as this context, but its
+ * environment may be modified independently and it may be accessed
+ * concurrently).
+ *
+ * @param a_rdn
+ * the name of the object to look up relative to this context
+ * @return the object bound to <tt>name</tt>
+ * @throws NamingException if a naming exception is encountered
+ *
+ * @see #lookup(String)
+ * @see #lookupLink(Name)
+ */
+ public Object lookup( Name a_rdn ) throws NamingException
+ {
+ return m_helper.lookup( a_rdn ) ;
+ }
+
+
+ /**
+ * Retrieves the named object.
+ * See {@link #lookup(Name)} for details.
+ * @param a_rdn
+ * the name of the object to look up relative to this context.
+ * @return the object bound to <tt>name</tt>
+ * @throws NamingException if a naming exception is encountered
+ */
+ public Object lookup( String a_rdn ) throws NamingException
+ {
+ return m_helper.lookup( a_rdn ) ;
+ }
+
+
+ /**
+ * Binds a name to an object.
+ * All intermediate contexts and the target context (that named by all
+ * but terminal atomic component of the name) must already exist.
+ *
+ * @param name
+ * the name to bind; may not be empty
+ * @param obj
+ * the object to bind; possibly null
+ * @throws NamingException if name is already bound
+ * @throws javax.naming.directory.InvalidAttributesException
+ * if object did not supply all mandatory attributes
+ * @throws NamingException if a naming exception is encountered
+ *
+ * @see #bind(String, Object)
+ * @see #rebind(Name, Object)
+ * @see javax.naming.directory.DirContext#bind(Name, Object,
+ * javax.naming.directory.Attributes)
+ */
+ public void bind(Name name, Object obj) throws NamingException
+ {
+ m_helper.bind(name, obj) ;
+ }
+
+
+ /**
+ * Binds a name to an object.
+ * See {@link #bind(Name, Object)} for details.
+ *
+ * @param name
+ * the name to bind; may not be empty
+ * @param obj
+ * the object to bind; possibly null
+ * @throws javax.naming.NameAlreadyBoundException if name is already bound
+ * @throws javax.naming.directory.InvalidAttributesException
+ * if object did not supply all mandatory attributes
+ * @throws NamingException if a naming exception is encountered
+ */
+ public void bind(String name, Object obj) throws NamingException
+ {
+ m_helper.bind(name, obj) ;
+ }
+
+
+ /**
+ * Binds a name to an object, overwriting any existing binding.
+ * All intermediate contexts and the target context (that named by all
+ * but terminal atomic component of the name) must already exist.
+ *
+ * <p> If the object is a <tt>DirContext</tt>, any existing attributes
+ * associated with the name are replaced with those of the object.
+ * Otherwise, any existing attributes associated with the name remain
+ * unchanged.
+ *
+ * @param name
+ * the name to bind; may not be empty
+ * @param obj
+ * the object to bind; possibly null
+ * @throws javax.naming.directory.InvalidAttributesException
+ * if object did not supply all mandatory attributes
+ * @throws NamingException if a naming exception is encountered
+ *
+ * @see #rebind(String, Object)
+ * @see #bind(Name, Object)
+ * @see javax.naming.directory.DirContext#rebind(Name, Object,
+ * javax.naming.directory.Attributes)
+ * @see <{DirContext}>
+ */
+ public void rebind(Name name, Object obj) throws NamingException
+ {
+ m_helper.rebind(name, obj) ;
+ }
+
+
+ /**
+ * Binds a name to an object, overwriting any existing binding.
+ * See {@link #rebind(Name, Object)} for details.
+ *
+ * @param name
+ * the name to bind; may not be empty
+ * @param obj
+ * the object to bind; possibly null
+ * @throws javax.naming.directory.InvalidAttributesException
+ * if object did not supply all mandatory attributes
+ * @throws NamingException if a naming exception is encountered
+ */
+ public void rebind(String name, Object obj) throws NamingException
+ {
+ m_helper.rebind(name, obj) ;
+ }
+
+
+ /**
+ * Unbinds the named object.
+ * Removes the terminal atomic name in <code>name</code>
+ * from the target context--that named by all but the terminal
+ * atomic part of <code>name</code>.
+ *
+ * <p> This method is idempotent.
+ * It succeeds even if the terminal atomic name
+ * is not bound in the target context, but throws
+ * <tt>NameNotFoundException</tt>
+ * if any of the intermediate contexts do not exist.
+ *
+ * <p> Any attributes associated with the name are removed.
+ * Intermediate contexts are not changed.
+ *
+ * @param name
+ * the name to unbind; may not be empty
+ * @throws javax.naming.NameNotFoundException if an intermediate context does not exist
+ * @throws NamingException if a naming exception is encountered
+ * @see #unbind(String)
+ */
+ public void unbind(Name name) throws NamingException
+ {
+ m_helper.unbind(name) ;
+ }
+
+
+ /**
+ * Unbinds the named object.
+ * See {@link #unbind(Name)} for details.
+ *
+ * @param name
+ * the name to unbind; may not be empty
+ * @throws javax.naming.NameNotFoundException if an intermediate context does not exist
+ * @throws NamingException if a naming exception is encountered
+ */
+ public void unbind(String name) throws NamingException
+ {
+ m_helper.unbind(name) ;
+ }
+
+
+ /**
+ * Binds a new name to the object bound to an old name, and unbinds
+ * the old name. Both names are relative to this context.
+ * Any attributes associated with the old name become associated
+ * with the new name.
+ * Intermediate contexts of the old name are not changed.
+ *
+ * @param oldName
+ * the name of the existing binding; may not be empty
+ * @param newName
+ * the name of the new binding; may not be empty
+ * @throws javax.naming.NameAlreadyBoundException if <tt>newName</tt> is already bound
+ * @throws NamingException if a naming exception is encountered
+ *
+ * @see #rename(String, String)
+ * @see #bind(Name, Object)
+ * @see #rebind(Name, Object)
+ */
+ public void rename(Name oldName, Name newName) throws NamingException
+ {
+ m_helper.rename(oldName, newName) ;
+ }
+
+
+ /**
+ * Binds a new name to the object bound to an old name, and unbinds
+ * the old name.
+ * See {@link #rename(Name, Name)} for details.
+ *
+ * @param oldName
+ * the name of the existing binding; may not be empty
+ * @param newName
+ * the name of the new binding; may not be empty
+ * @throws javax.naming.NameAlreadyBoundException if <tt>newName</tt> is already bound
+ * @throws NamingException if a naming exception is encountered
+ */
+ public void rename(String oldName, String newName) throws NamingException
+ {
+ m_helper.rename(oldName, newName) ;
+ }
+
+
+ /**
+ * Enumerates the names bound in the named context, along with the
+ * class names of objects bound to them.
+ * The contents of any subcontexts are not included.
+ *
+ * <p> If a binding is added to or removed from this context,
+ * its effect on an enumeration previously returned is undefined.
+ *
+ * @param name
+ * the name of the context to list
+ * @return an enumeration of the names and class names of the
+ * bindings in this context. Each element of the
+ * enumeration is of type <tt>NameClassPair</tt>.
+ * @throws NamingException if a naming exception is encountered
+ *
+ * @see #list(String)
+ * @see #listBindings(Name)
+ * @see javax.naming.NameClassPair
+ */
+ public NamingEnumeration list(Name name) throws NamingException
+ {
+ return m_helper.list(name) ;
+ }
+
+
+ /**
+ * Enumerates the names bound in the named context, along with the
+ * class names of objects bound to them.
+ * See {@link #list(Name)} for details.
+ *
+ * @param name
+ * the name of the context to list
+ * @return an enumeration of the names and class names of the
+ * bindings in this context. Each element of the
+ * enumeration is of type <tt>NameClassPair</tt>.
+ * @throws NamingException if a naming exception is encountered
+ */
+ public NamingEnumeration list(String name) throws NamingException
+ {
+ return m_helper.list(name) ;
+ }
+
+
+ /**
+ * Enumerates the names bound in the named context, along with the
+ * objects bound to them.
+ * The contents of any subcontexts are not included.
+ *
+ * <p> If a binding is added to or removed from this context,
+ * its effect on an enumeration previously returned is undefined.
+ *
+ * @param name
+ * the name of the context to list
+ * @return an enumeration of the bindings in this context.
+ * Each element of the enumeration is of type
+ * <tt>Binding</tt>.
+ * @throws NamingException if a naming exception is encountered
+ *
+ * @see #listBindings(String)
+ * @see #list(Name)
+ * @see javax.naming.Binding
+ */
+ public NamingEnumeration listBindings(Name name) throws NamingException
+ {
+ return m_helper.listBindings(name) ;
+ }
+
+
+ /**
+ * Enumerates the names bound in the named context, along with the
+ * objects bound to them.
+ * See {@link #listBindings(Name)} for details.
+ *
+ * @param name
+ * the name of the context to list
+ * @return an enumeration of the bindings in this context.
+ * Each element of the enumeration is of type
+ * <tt>Binding</tt>.
+ * @throws NamingException if a naming exception is encountered
+ */
+ public NamingEnumeration listBindings(String name) throws NamingException
+ {
+ return m_helper.listBindings(name) ;
+ }
+
+
+ /**
+ * Destroys the named context and removes it from the namespace.
+ * Any attributes associated with the name are also removed.
+ * Intermediate contexts are not destroyed.
+ *
+ * <p> This method is idempotent.
+ * It succeeds even if the terminal atomic name
+ * is not bound in the target context, but throws
+ * <tt>NameNotFoundException</tt>
+ * if any of the intermediate contexts do not exist.
+ *
+ * <p> In a federated naming system, a context from one naming system
+ * may be bound to a name in another. One can subsequently
+ * look up and perform operations on the foreign context using a
+ * composite name. However, an attempt destroy the context using
+ * this composite name will fail with
+ * <tt>NotContextException</tt>, because the foreign context is not
+ * a "subcontext" of the context in which it is bound.
+ * Instead, use <tt>unbind()</tt> to remove the
+ * binding of the foreign context. Destroying the foreign context
+ * requires that the <tt>destroySubcontext()</tt> be performed
+ * on a context from the foreign context's "native" naming system.
+ *
+ * @param name
+ * the name of the context to be destroyed; may not be empty
+ * @throws javax.naming.NameNotFoundException if an intermediate context does not exist
+ * @throws javax.naming.NotContextException if the name is bound but does not name a
+ * context, or does not name a context of the appropriate type
+ * @throws javax.naming.ContextNotEmptyException if the named context is not empty
+ * @throws NamingException if a naming exception is encountered
+ *
+ * @see #destroySubcontext(String)
+ */
+ public void destroySubcontext( Name name ) throws NamingException
+ {
+ m_helper.destroySubcontext( name ) ;
+ }
+
+
+ /**
+ * Destroys the named context and removes it from the namespace.
+ * See {@link #destroySubcontext(Name)} for details.
+ *
+ * @param name
+ * the name of the context to be destroyed; may not be empty
+ * @throws javax.naming.NameNotFoundException if an intermediate context does not exist
+ * @throws javax.naming.NotContextException if the name is bound but does not name a
+ * context, or does not name a context of the appropriate type
+ * @throws javax.naming.ContextNotEmptyException if the named context is not empty
+ * @throws NamingException if a naming exception is encountered
+ */
+ public void destroySubcontext( String name ) throws NamingException
+ {
+ m_helper.destroySubcontext( name ) ;
+ }
+
+
+ /**
+ * Creates and binds a new context.
+ * Creates a new context with the given name and binds it in
+ * the target context (that named by all but terminal atomic
+ * component of the name). All intermediate contexts and the
+ * target context must already exist.
+ *
+ * @param a_name
+ * the name of the context to create; may not be empty
+ * @return the newly created context
+ *
+ * @throws javax.naming.NameAlreadyBoundException if name is already bound
+ * @throws javax.naming.directory.InvalidAttributesException
+ * if creation of the subcontext requires specification of
+ * mandatory attributes
+ * @throws NamingException if a naming exception is encountered
+ *
+ * @see #createSubcontext(String)
+ * @see javax.naming.directory.DirContext#createSubcontext
+ */
+ public Context createSubcontext( Name a_name )
+ throws NamingException
+ {
+ return m_helper.createSubcontext( a_name ) ;
+ }
+
+
+ /**
+ * Creates and binds a new context.
+ * See {@link #createSubcontext(Name)} for details.
+ *
+ * @param a_name
+ * the name of the context to create; may not be empty
+ * @return the newly created context
+ *
+ * @throws javax.naming.NameAlreadyBoundException if name is already bound
+ * @throws javax.naming.directory.InvalidAttributesException
+ * if creation of the subcontext requires specification of
+ * mandatory attributes
+ * @throws NamingException if a naming exception is encountered
+ */
+ public Context createSubcontext( String a_name )
+ throws NamingException
+ {
+ return m_helper.createSubcontext( a_name ) ;
+ }
+
+
+ /**
+ * Retrieves the named object, following links except
+ * for the terminal atomic component of the name.
+ * If the object bound to <tt>name</tt> is not a link,
+ * returns the object itself.
+ *
+ * @param name
+ * the name of the object to look up
+ * @return the object bound to <tt>name</tt>, not following the
+ * terminal link (if any).
+ * @throws NamingException if a naming exception is encountered
+ *
+ * @see #lookupLink(String)
+ */
+ public Object lookupLink(Name name) throws NamingException
+ {
+ throw new UnsupportedOperationException() ;
+ }
+
+
+ /**
+ * Retrieves the named object, following links except
+ * for the terminal atomic component of the name.
+ * See {@link #lookupLink(Name)} for details.
+ *
+ * @param name
+ * the name of the object to look up
+ * @return the object bound to <tt>name</tt>, not following the
+ * terminal link (if any)
+ * @throws NamingException if a naming exception is encountered
+ */
+ public Object lookupLink(String name) throws NamingException
+ {
+ throw new UnsupportedOperationException() ;
+ }
+
+
+ /**
+ * Retrieves the parser associated with the named context.
+ * In a federation of namespaces, different naming systems will
+ * parse names differently. This method allows an application
+ * to get a parser for parsing names into their atomic components
+ * using the naming convention of a particular naming system.
+ * Within any single naming system, <tt>NameParser</tt> objects
+ * returned by this method must be equal (using the <tt>equals()</tt>
+ * test).
+ *
+ * @param a_rdn
+ * the name of the context from which to get the parser
+ * @return a name parser that can parse compound names into their atomic
+ * components
+ * @throws NamingException if a naming exception is encountered
+ *
+ * @see #getNameParser(String)
+ * @see javax.naming.CompoundName
+ */
+ public NameParser getNameParser( Name a_rdn ) throws NamingException
+ {
+ Name l_dn = new LdapName() ;
+ l_dn.addAll( m_entry.getNormalizedDN() ) ;
+ l_dn.addAll( a_rdn ) ;
+
+ JndiProviderModule l_provider = JndiProviderModule.getInstance() ;
+ UnifiedBackend l_nexus = l_provider.getNexus() ;
+ return l_nexus.getNormalizingParser( l_dn ) ;
+ }
+
+
+ /**
+ * Retrieves the parser associated with the named context.
+ * See {@link #getNameParser(Name)} for details.
+ *
+ * @param a_rdn
+ * the name of the context from which to get the parser
+ * @return a name parser that can parse compound names into their atomic
+ * components
+ * @throws NamingException if a naming exception is encountered
+ */
+ public NameParser getNameParser( String a_rdn ) throws NamingException
+ {
+ JndiProviderModule l_provider = JndiProviderModule.getInstance() ;
+ UnifiedBackend l_nexus = l_provider.getNexus() ;
+ return getNameParser( l_nexus.getNormalizedName( a_rdn ) ) ;
+ }
+
+
+ /**
+ * Composes the name of this context with a name relative to
+ * this context.
+ * Given a name (<code>name</code>) relative to this context, and
+ * the name (<code>prefix</code>) of this context relative to one
+ * of its ancestors, this method returns the composition of the
+ * two names using the syntax appropriate for the naming
+ * system(s) involved. That is, if <code>name</code> names an
+ * object relative to this context, the result is the name of the
+ * same object, but relative to the ancestor context. None of the
+ * names may be null.
+ * <p>
+ * For example, if this context is named "wiz.com" relative
+ * to the initial context, then
+ * <pre>
+ * composeName("east", "wiz.com") </pre>
+ * might return <code>"east.wiz.com"</code>.
+ * If instead this context is named "org/research", then
+ * <pre>
+ * composeName("user/jane", "org/research") </pre>
+ * might return <code>"org/research/user/jane"</code> while
+ * <pre>
+ * composeName("user/jane", "research") </pre>
+ * returns <code>"research/user/jane"</code>.
+ *
+ * @param name
+ * a name relative to this context
+ * @param prefix
+ * the name of this context relative to one of its ancestors
+ * @return the composition of <code>prefix</code> and <code>name</code>
+ * @throws NamingException if a naming exception is encountered
+ *
+ * @see #composeName(String, String)
+ */
+ public Name composeName(Name name, Name prefix)
+ throws NamingException
+ {
+ return m_helper.composeName(name, prefix) ;
+ }
+
+
+ /**
+ * Composes the name of this context with a name relative to
+ * this context.
+ * See {@link #composeName(Name, Name)} for details.
+ *
+ * @param name
+ * a name relative to this context
+ * @param prefix
+ * the name of this context relative to one of its ancestors
+ * @return the composition of <code>prefix</code> and <code>name</code>
+ * @throws NamingException if a naming exception is encountered
+ */
+ public String composeName(String name, String prefix)
+ throws NamingException
+ {
+ return m_helper.composeName(name, prefix) ;
+ }
+
+
+ /**
+ * Adds a new environment property to the environment of this
+ * context. If the property already exists, its value is overwritten.
+ * See class description for more details on environment properties.
+ *
+ * @param propName
+ * the name of the environment property to add; may not be null
+ * @param propVal
+ * the value of the property to add; may not be null
+ * @return the previous value of the property, or null if the property was
+ * not in the environment before
+ * @throws NamingException if a naming exception is encountered
+ *
+ * @see #getEnvironment()
+ * @see #removeFromEnvironment(String)
+ */
+ public Object addToEnvironment(String propName, Object propVal)
+ throws NamingException
+ {
+ return m_env.put(propName, propVal) ;
+ }
+
+
+ /**
+ * Removes an environment property from the environment of this
+ * context. See class description for more details on environment
+ * properties.
+ *
+ * @param propName
+ * the name of the environment property to remove; may not be null
+ * @return the previous value of the property, or null if the property was
+ * not in the environment
+ * @throws NamingException if a naming exception is encountered
+ *
+ * @see #getEnvironment()
+ * @see #addToEnvironment(String, Object)
+ */
+ public Object removeFromEnvironment(String propName)
+ throws NamingException
+ {
+ return m_env.remove(propName) ;
+ }
+
+
+ /**
+ * Retrieves the environment in effect for this context.
+ * See class description for more details on environment properties.
+ *
+ * <p> The caller should not make any changes to the object returned:
+ * their effect on the context is undefined.
+ * The environment of this context may be changed using
+ * <tt>addToEnvironment()</tt> and <tt>removeFromEnvironment()</tt>.
+ *
+ * @return the environment of this context; never null
+ * @throws NamingException if a naming exception is encountered
+ *
+ * @see #addToEnvironment(String, Object)
+ * @see #removeFromEnvironment(String)
+ */
+ public Hashtable getEnvironment() throws NamingException
+ {
+ return this.m_env ;
+ }
+
+
+ /**
+ * Closes this context.
+ * This method releases this context's resources immediately, instead of
+ * waiting for them to be released automatically by the garbage collector.
+ *
+ * <p> This method is idempotent: invoking it on a context that has
+ * already been closed has no effect. Invoking any other method
+ * on a closed context is not allowed, and results in undefined behaviour.
+ *
+ * @throws NamingException if a naming exception is encountered
+ */
+ public void close() throws NamingException
+ {
+ // Does nothing for now
+ }
+
+
+ /**
+ * Retrieves the full name of this context within its own namespace.
+ *
+ * <p> Many naming services have a notion of a "full name" for objects
+ * in their respective namespaces. For example, an LDAP entry has
+ * a distinguished name, and a DNS record has a fully qualified name.
+ * This method allows the client application to retrieve this name.
+ * The string returned by this method is not a JNDI composite name
+ * and should not be passed directly to context methods.
+ * In naming systems for which the notion of full name does not
+ * make sense, <tt>OperationNotSupportedException</tt> is thrown.
+ *
+ * @return this context's name in its own namespace; never null
+ * @throws javax.naming.OperationNotSupportedException if the naming system does
+ * not have the notion of a full name
+ * @throws NamingException if a naming exception is encountered
+ *
+ * @since 1.3
+ */
+ public String getNameInNamespace() throws NamingException
+ {
+ return m_entry.getEntryDN() ;
+ }
+
+
+ public Object clone()
+ {
+ try
+ {
+ // Every context other than the default on the RootDSE will have
+ // a non-zero relative distinguished name.
+ if( m_rdn.size() > 0 )
+ {
+ return new UnifiedLdapContext( m_env, m_entry ) ;
+ }
+
+ return new UnifiedLdapContext( m_env ) ;
+ }
+ catch( NamingException e )
+ {
+ e.printStackTrace() ;
+ // Should log something here.
+ return null ;
+ }
+ }
+
+
+ // ------------------------------------------------------------------------
+ // Package Friendly Methods Used By ContextHelper Class
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Gets the LdapEntry represented by this Context.
+ *
+ * @return this contexts associated LdapEntry
+ */
+ LdapEntry getEntry()
+ {
+ return m_entry ;
+ }
+
+
+ void threadAssociate()
+ {
+ JndiProviderModule l_provider = JndiProviderModule.getInstance() ;
+ ClientManager l_clientManager = l_provider.getClientManager() ;
+
+ // We only want to associate threads that are not protocol module worker
+ // threads. Protocol module worker threads have client keys so if the
+ // key is null we can associate this thread with the client manager.
+ if( l_clientManager.getClientKey() == null )
+ {
+ l_clientManager.threadAssociate( ( LdapContext ) this ) ;
+ }
+ }
+
+
+ void threadDisassociate()
+ {
+ JndiProviderModule l_provider = JndiProviderModule.getInstance() ;
+ ClientManager l_clientManager = l_provider.getClientManager() ;
+
+ // We only want to disassociate threads that are not protocol module
+ // worker threads and have registered themselves. Protocol module
+ // worker threads have client keys so if the key is null we can
+ // disassociate this thread with the client manager. We also prevent
+ // disassociation if the context has changed.
+
+ // If a cascade of JNDI activity is caused by triggers, synchronous
+ // processing will cause the overright of the first associated context
+ // with Contexts used in trigger bodies. This is the case if the
+ // trigger fires before an operation occurs. Once the cascade
+ // is over code relying on Context to be the same will have a handle on
+ // the wrong context. This is a serious flaw in this design.
+
+ // We could maintain a stack of Contexts on the ClientManager. When
+ // a thread is associated with a context a check is made to determine
+ // if it already is associated with another context. If so the old
+ // context is pushed onto the stack and the new context is associated.
+ // Disassociations remove the associated Context and reassociate older
+ // Contexts by popping them off the stack. This way a cascade before
+ // an operation which may oust the first Context, will reinstate it
+ // when the cascade terminates.
+
+ // Also note that dropping a client will make the key go away and the
+ // JNDI provider will suddenly presume the thread of execution not to be
+ // a protocol module worker thread. This may completely confuse correct
+ // operation. At this point I'm seriously reconsidering this facility.
+
+ if( l_clientManager.getClientKey() == null
+ && l_clientManager.getLdapContext() == this )
+ {
+ l_clientManager.threadDisassociate() ;
+ }
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/jndi/UnifiedDirContext.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/jndi/UnifiedDirContext.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,987 @@
+/*
+ * $Id: UnifiedDirContext.java,v 1.10 2003/08/22 21:15:55 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.jndi ;
+
+
+import java.util.Hashtable ;
+
+import javax.naming.Name ;
+import javax.naming.Context ;
+import javax.naming.NamingException ;
+import javax.naming.NamingEnumeration ;
+
+import javax.naming.directory.Attributes ;
+import javax.naming.directory.DirContext ;
+import javax.naming.directory.SearchControls ;
+import javax.naming.directory.ModificationItem ;
+
+import org.apache.eve.backend.LdapEntry ;
+
+
+/**
+ * The internal server side LdapContext implementation used to access and
+ * modify server entries. Most bind operations will be unsupported since
+ * instances of this context are already bound. This context is the main
+ * class of the internal server side provider. It is used whenever an
+ * initial context is requested within stored procedures or within a
+ * server trigger. It is also the basis for server side communication between
+ * a server host with an embedded ldapd server component. The UnifiedBackend
+ * as well as a public Kernel interface will expose a handle to the RootDSE
+ * using this LdapContext implementation.
+ *
+ * Note that the documentation used by the Java APIs for Context, DirContext
+ * and LdapContext are copied here for convenience. Eventually we can make
+ * these chunks of javadocs @see references to the respective interfaces.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.10 $
+ */
+public abstract class UnifiedDirContext
+ extends UnifiedContext
+ implements DirContext
+{
+ private final DirContextHelper m_helper ;
+
+
+ protected UnifiedDirContext( Hashtable an_environment )
+ {
+ super( an_environment ) ;
+ m_helper = new DirContextHelper( this ) ;
+ }
+
+
+ protected UnifiedDirContext( Hashtable an_environment, LdapEntry a_entry )
+ throws NamingException
+ {
+ super( an_environment, a_entry ) ;
+ m_helper = new DirContextHelper( this ) ;
+ }
+
+
+ ////////////////////////////////
+ // DirContext Implementations //
+ ////////////////////////////////
+
+
+ /**
+ * Retrieves all of the attributes associated with a named object.
+ * See the class description regarding attribute models, attribute
+ * type names, and operational attributes.
+ *
+ * @param name
+ * the name of the object from which to retrieve attributes
+ * @return the set of attributes associated with <code>name</code>.
+ * Returns an empty attribute set if name has no attributes;
+ * never null.
+ * @throws NamingException if a naming exception is encountered
+ *
+ * @see #getAttributes(String)
+ * @see #getAttributes(Name, String[])
+ */
+ public Attributes getAttributes(Name name) throws NamingException
+ {
+ return m_helper.getAttributes(name) ;
+ }
+
+
+ /**
+ * Retrieves all of the attributes associated with a named object.
+ * See {@link #getAttributes(Name)} for details.
+ *
+ * @param name
+ * the name of the object from which to retrieve attributes
+ * @return the set of attributes associated with <code>name</code>
+ *
+ * @throws NamingException if a naming exception is encountered
+ */
+ public Attributes getAttributes(String name) throws NamingException
+ {
+ return m_helper.getAttributes(name) ;
+ }
+
+
+ /**
+ * Retrieves selected attributes associated with a named object.
+ * See the class description regarding attribute models, attribute
+ * type names, and operational attributes.
+ *
+ * <p> If the object does not have an attribute
+ * specified, the directory will ignore the nonexistent attribute
+ * and return those requested attributes that the object does have.
+ *
+ * <p> A directory might return more attributes than was requested
+ * (see <strong>Attribute Type Names</strong> in the class description),
+ * but is not allowed to return arbitrary, unrelated attributes.
+ *
+ * <p> See also <strong>Operational Attributes</strong> in the class
+ * description.
+ *
+ * @param name
+ * the name of the object from which to retrieve attributes
+ * @param attrIds
+ * the identifiers of the attributes to retrieve.
+ * null indicates that all attributes should be retrieved;
+ * an empty array indicates that none should be retrieved.
+ * @return the requested attributes; never null
+ *
+ * @throws NamingException if a naming exception is encountered
+ */
+ public Attributes getAttributes(Name name, String[] attrIds)
+ throws NamingException
+ {
+ return m_helper.getAttributes(name, attrIds) ;
+ }
+
+
+ /**
+ * Retrieves selected attributes associated with a named object.
+ * See {@link #getAttributes(Name, String[])} for details.
+ *
+ * @param name
+ * The name of the object from which to retrieve attributes
+ * @param attrIds
+ * the identifiers of the attributes to retrieve.
+ * null indicates that all attributes should be retrieved;
+ * an empty array indicates that none should be retrieved.
+ * @return the requested attributes; never null
+ *
+ * @throws NamingException if a naming exception is encountered
+ */
+ public Attributes getAttributes(String name, String[] attrIds)
+ throws NamingException
+ {
+ return m_helper.getAttributes(name, attrIds) ;
+ }
+
+
+ /**
+ * Modifies the attributes associated with a named object.
+ * The order of the modifications is not specified. Where
+ * possible, the modifications are performed atomically.
+ *
+ * @param name
+ * the name of the object whose attributes will be updated
+ * @param mod_op
+ * the modification operation, one of:
+ * <code>ADD_ATTRIBUTE</code>,
+ * <code>REPLACE_ATTRIBUTE</code>,
+ * <code>REMOVE_ATTRIBUTE</code>.
+ * @param attrs
+ * the attributes to be used for the modification; may not be null
+ *
+ * @throws javax.naming.directory.AttributeModificationException if the modification cannot
+ * be completed successfully
+ * @throws NamingException if a naming exception is encountered
+ *
+ * @see #modifyAttributes(Name, ModificationItem[])
+ */
+ public void modifyAttributes(Name name, int mod_op, Attributes attrs)
+ throws NamingException
+ {
+ m_helper.modifyAttributes(name, mod_op, attrs) ;
+ }
+
+
+ /**
+ * Modifies the attributes associated with a named object.
+ * See {@link #modifyAttributes(Name, int, Attributes)} for details.
+ *
+ * @param name
+ * the name of the object whose attributes will be updated
+ * @param mod_op
+ * the modification operation, one of:
+ * <code>ADD_ATTRIBUTE</code>,
+ * <code>REPLACE_ATTRIBUTE</code>,
+ * <code>REMOVE_ATTRIBUTE</code>.
+ * @param attrs
+ * the attributes to be used for the modification; map not be null
+ *
+ * @throws javax.naming.directory.AttributeModificationException if the modification cannot
+ * be completed successfully
+ * @throws NamingException if a naming exception is encountered
+ */
+ public void modifyAttributes(String name, int mod_op, Attributes attrs)
+ throws NamingException
+ {
+ m_helper.modifyAttributes(name, mod_op, attrs) ;
+ }
+
+
+ /**
+ * Modifies the attributes associated with a named object using
+ * an ordered list of modifications.
+ * The modifications are performed
+ * in the order specified. Each modification specifies a
+ * modification operation code and an attribute on which to
+ * operate. Where possible, the modifications are
+ * performed atomically.
+ *
+ * @param name
+ * the name of the object whose attributes will be updated
+ * @param mods
+ * an ordered sequence of modifications to be performed;
+ * may not be null
+ *
+ * @throws javax.naming.directory.AttributeModificationException if the modifications
+ * cannot be completed successfully
+ * @throws NamingException if a naming exception is encountered
+ *
+ * @see #modifyAttributes(Name, int, Attributes)
+ * @see <{ModificationItem}>
+ */
+ public void modifyAttributes(Name name, ModificationItem[] mods)
+ throws NamingException
+ {
+ m_helper.modifyAttributes(name, mods) ;
+ }
+
+
+ /**
+ * Modifies the attributes associated with a named object using
+ * an ordered list of modifications.
+ * See {@link #modifyAttributes(Name, ModificationItem[])} for details.
+ *
+ * @param name
+ * the name of the object whose attributes will be updated
+ * @param mods
+ * an ordered sequence of modifications to be performed;
+ * may not be null
+ *
+ * @throws javax.naming.directory.AttributeModificationException if the modifications
+ * cannot be completed successfully
+ * @throws NamingException if a naming exception is encountered
+ */
+ public void modifyAttributes(String name, ModificationItem[] mods)
+ throws NamingException
+ {
+ m_helper.modifyAttributes(name, mods) ;
+ }
+
+
+ /**
+ * Binds a name to an object, along with associated attributes.
+ * If <tt>attrs</tt> is null, the resulting binding will have
+ * the attributes associated with <tt>obj</tt> if <tt>obj</tt> is a
+ * <tt>DirContext</tt>, and no attributes otherwise.
+ * If <tt>attrs</tt> is non-null, the resulting binding will have
+ * <tt>attrs</tt> as its attributes; any attributes associated with
+ * <tt>obj</tt> are ignored.
+ *
+ * @param name
+ * the name to bind; may not be empty
+ * @param obj
+ * the object to bind; possibly null
+ * @param attrs
+ * the attributes to associate with the binding
+ *
+ * @throws javax.naming.NameAlreadyBoundException if name is already bound
+ * @throws javax.naming.directory.InvalidAttributesException if some "mandatory" attributes
+ * of the binding are not supplied
+ * @throws NamingException if a naming exception is encountered
+ *
+ * @see Context#bind(Name, Object)
+ * @see #rebind(Name, Object, Attributes)
+ */
+ public void bind(Name name, Object obj, Attributes attrs)
+ throws NamingException
+ {
+ m_helper.bind(name, obj, attrs) ;
+ }
+
+
+ /**
+ * Binds a name to an object, along with associated attributes.
+ * See {@link #bind(Name, Object, Attributes)} for details.
+ *
+ * @param name
+ * the name to bind; may not be empty
+ * @param obj
+ * the object to bind; possibly null
+ * @param attrs
+ * the attributes to associate with the binding
+ *
+ * @throws javax.naming.NameAlreadyBoundException if name is already bound
+ * @throws javax.naming.directory.InvalidAttributesException if some "mandatory" attributes
+ * of the binding are not supplied
+ * @throws NamingException if a naming exception is encountered
+ */
+ public void bind(String name, Object obj, Attributes attrs)
+ throws NamingException
+ {
+ m_helper.bind(name, obj, attrs) ;
+ }
+
+
+ /**
+ * Binds a name to an object, along with associated attributes,
+ * overwriting any existing binding.
+ * If <tt>attrs</tt> is null and <tt>obj</tt> is a <tt>DirContext</tt>,
+ * the attributes from <tt>obj</tt> are used.
+ * If <tt>attrs</tt> is null and <tt>obj</tt> is not a <tt>DirContext</tt>,
+ * any existing attributes associated with the object already bound
+ * in the directory remain unchanged.
+ * If <tt>attrs</tt> is non-null, any existing attributes associated with
+ * the object already bound in the directory are removed and <tt>attrs</tt>
+ * is associated with the named object. If <tt>obj</tt> is a
+ * <tt>DirContext</tt> and <tt>attrs</tt> is non-null, the attributes
+ * of <tt>obj</tt> are ignored.
+ *
+ * @param name
+ * the name to bind; may not be empty
+ * @param obj
+ * the object to bind; possibly null
+ * @param attrs
+ * the attributes to associate with the binding
+ *
+ * @throws javax.naming.directory.InvalidAttributesException if some "mandatory" attributes
+ * of the binding are not supplied
+ * @throws NamingException if a naming exception is encountered
+ *
+ * @see Context#bind(Name, Object)
+ * @see #bind(Name, Object, Attributes)
+ */
+ public void rebind(Name name, Object obj, Attributes attrs)
+ throws NamingException
+ {
+ m_helper.rebind(name, obj, attrs) ;
+ }
+
+
+ /**
+ * Binds a name to an object, along with associated attributes,
+ * overwriting any existing binding.
+ * See {@link #rebind(Name, Object, Attributes)} for details.
+ *
+ * @param name
+ * the name to bind; may not be empty
+ * @param obj
+ * the object to bind; possibly null
+ * @param attrs
+ * the attributes to associate with the binding
+ *
+ * @throws javax.naming.directory.InvalidAttributesException if some "mandatory" attributes
+ * of the binding are not supplied
+ * @throws NamingException if a naming exception is encountered
+ */
+ public void rebind(String name, Object obj, Attributes attrs)
+ throws NamingException
+ {
+ m_helper.rebind(name, obj, attrs) ;
+ }
+
+
+ /**
+ * Creates and binds a new context, along with associated attributes.
+ * This method creates a new subcontext with the given name, binds it in
+ * the target context (that named by all but terminal atomic
+ * component of the name), and associates the supplied attributes
+ * with the newly created object.
+ * All intermediate and target contexts must already exist.
+ * If <tt>attrs</tt> is null, this method is equivalent to
+ * <tt>Context.createSubcontext()</tt>.
+ *
+ * @param a_name
+ * the name of the context to create; may not be empty
+ * @param a_attrs
+ * the attributes to associate with the newly created context
+ * @return the newly created context
+ *
+ * @throws javax.naming.NameAlreadyBoundException if the name is already bound
+ * @throws javax.naming.directory.InvalidAttributesException if <code>attrs</code> does not
+ * contain all the mandatory attributes required for creation
+ * @throws NamingException if a naming exception is encountered
+ *
+ * @see Context#createSubcontext(Name)
+ */
+ public DirContext createSubcontext( Name a_name, Attributes a_attrs )
+ throws NamingException
+ {
+ return m_helper.createSubcontext( a_name, a_attrs) ;
+ }
+
+
+ /**
+ * Creates and binds a new context, along with associated attributes.
+ * See {@link #createSubcontext(Name, Attributes)} for details.
+ *
+ * @param a_name
+ * the name of the context to create; may not be empty
+ * @param a_attrs
+ * the attributes to associate with the newly created context
+ * @return the newly created context
+ *
+ * @throws javax.naming.NameAlreadyBoundException if the name is already bound
+ * @throws javax.naming.directory.InvalidAttributesException if <code>attrs</code> does not
+ * contain all the mandatory attributes required for creation
+ * @throws NamingException if a naming exception is encountered
+ */
+ public DirContext createSubcontext( String a_name, Attributes a_attrs )
+ throws NamingException
+ {
+ return m_helper.createSubcontext( a_name, a_attrs ) ;
+ }
+
+
+ ///////////////////////
+ // Schema Operations //
+ ///////////////////////
+
+
+ /**
+ * Retrieves the schema associated with the named object.
+ * The schema describes rules regarding the structure of the namespace
+ * and the attributes stored within it. The schema
+ * specifies what types of objects can be added to the directory and where
+ * they can be added; what mandatory and optional attributes an object
+ * can have. The range of support for schemas is directory-specific.
+ *
+ * <p> This method returns the root of the schema information tree
+ * that is applicable to the named object. Several named objects
+ * (or even an entire directory) might share the same schema.
+ *
+ * <p> Issues such as structure and contents of the schema tree,
+ * permission to modify to the contents of the schema
+ * tree, and the effect of such modifications on the directory
+ * are dependent on the underlying directory.
+ *
+ * @param name
+ * the name of the object whose schema is to be retrieved
+ * @return the schema associated with the context; never null
+ * @throws javax.naming.OperationNotSupportedException if schema not supported
+ * @throws NamingException if a naming exception is encountered
+ */
+ public DirContext getSchema(Name name) throws NamingException
+ {
+ throw new UnsupportedOperationException() ;
+ }
+
+
+ /**
+ * Retrieves the schema associated with the named object.
+ * See {@link #getSchema(Name)} for details.
+ *
+ * @param name
+ * the name of the object whose schema is to be retrieved
+ * @return the schema associated with the context; never null
+ * @throws javax.naming.OperationNotSupportedException if schema not supported
+ * @throws NamingException if a naming exception is encountered
+ */
+ public DirContext getSchema(String name) throws NamingException
+ {
+ throw new UnsupportedOperationException() ;
+ }
+
+
+ /**
+ * Retrieves a context containing the schema objects of the
+ * named object's class definitions.
+ *<p>
+ * One category of information found in directory schemas is
+ * <em>class definitions</em>. An "object class" definition
+ * specifies the object's <em>type</em> and what attributes (mandatory
+ * and optional) the object must/can have. Note that the term
+ * "object class" being referred to here is in the directory sense
+ * rather than in the Java sense.
+ * For example, if the named object is a directory object of
+ * "Person" class, <tt>getSchemaClassDefinition()</tt> would return a
+ * <tt>DirContext</tt> representing the (directory's) object class
+ * definition of "Person".
+ *<p>
+ * The information that can be retrieved from an object class definition
+ * is directory-dependent.
+ *<p>
+ * Prior to JNDI 1.2, this method
+ * returned a single schema object representing the class definition of
+ * the named object.
+ * Since JNDI 1.2, this method returns a <tt>DirContext</tt> containing
+ * all of the named object's class definitions.
+ *
+ * @param name
+ * the name of the object whose object class
+ * definition is to be retrieved
+ * @return the <tt>DirContext</tt> containing the named
+ * object's class definitions; never null
+ *
+ * @throws javax.naming.OperationNotSupportedException if schema not supported
+ * @throws NamingException if a naming exception is encountered
+ */
+ public DirContext getSchemaClassDefinition(Name name)
+ throws NamingException
+ {
+ throw new UnsupportedOperationException() ;
+ }
+
+
+ /**
+ * Retrieves a context containing the schema objects of the
+ * named object's class definitions.
+ * See {@link #getSchemaClassDefinition(Name)} for details.
+ *
+ * @param name
+ * the name of the object whose object class
+ * definition is to be retrieved
+ * @return the <tt>DirContext</tt> containing the named
+ * object's class definitions; never null
+ *
+ * @throws javax.naming.OperationNotSupportedException if schema not supported
+ * @throws NamingException if a naming exception is encountered
+ */
+ public DirContext getSchemaClassDefinition(String name)
+ throws NamingException
+ {
+ throw new UnsupportedOperationException() ;
+ }
+
+
+ ///////////////////////
+ // Search Operations //
+ ///////////////////////
+
+
+ /**
+ * Searches in a single context for objects that contain a
+ * specified set of attributes, and retrieves selected attributes.
+ * The search is performed using the default
+ * <code>SearchControls</code> settings.
+ * <p>
+ * For an object to be selected, each attribute in
+ * <code>matchingAttributes</code> must match some attribute of the
+ * object. If <code>matchingAttributes</code> is empty or
+ * null, all objects in the target context are returned.
+ *<p>
+ * An attribute <em>A</em><sub>1</sub> in
+ * <code>matchingAttributes</code> is considered to match an
+ * attribute <em>A</em><sub>2</sub> of an object if
+ * <em>A</em><sub>1</sub> and <em>A</em><sub>2</sub> have the same
+ * identifier, and each value of <em>A</em><sub>1</sub> is equal
+ * to some value of <em>A</em><sub>2</sub>. This implies that the
+ * order of values is not significant, and that
+ * <em>A</em><sub>2</sub> may contain "extra" values not found in
+ * <em>A</em><sub>1</sub> without affecting the comparison. It
+ * also implies that if <em>A</em><sub>1</sub> has no values, then
+ * testing for a match is equivalent to testing for the presence
+ * of an attribute <em>A</em><sub>2</sub> with the same
+ * identifier.
+ *<p>
+ * The precise definition of "equality" used in comparing attribute values
+ * is defined by the underlying directory service. It might use the
+ * <code>Object.equals</code> method, for example, or might use a schema
+ * to specify a different equality operation.
+ * For matching based on operations other than equality (such as
+ * substring comparison) use the version of the <code>search</code>
+ * method that takes a filter argument.
+ * <p>
+ * When changes are made to this <tt>DirContext</tt>,
+ * the effect on enumerations returned by prior calls to this method
+ * is undefined.
+ *<p>
+ * If the object does not have the attribute
+ * specified, the directory will ignore the nonexistent attribute
+ * and return the requested attributes that the object does have.
+ *<p>
+ * A directory might return more attributes than was requested
+ * (see <strong>Attribute Type Names</strong> in the class description),
+ * but is not allowed to return arbitrary, unrelated attributes.
+ *<p>
+ * See also <strong>Operational Attributes</strong> in the class
+ * description.
+ *
+ * @param name
+ * the name of the context to search
+ * @param matchingAttributes
+ * the attributes to search for. If empty or null,
+ * all objects in the target context are returned.
+ * @param attributesToReturn
+ * the attributes to return. null indicates that
+ * all attributes are to be returned;
+ * an empty array indicates that none are to be returned.
+ * @return
+ * a non-null enumeration of <tt>SearchResult</tt> objects.
+ * Each <tt>SearchResult</tt> contains the attributes
+ * identified by <code>attributesToReturn</code>
+ * and the name of the corresponding object, named relative
+ * to the context named by <code>name</code>.
+ * @throws NamingException if a naming exception is encountered
+ *
+ * @see <{SearchControls}>
+ * @see javax.naming.directory.SearchResult
+ * @see #search(Name, String, Object[], SearchControls)
+ */
+ public NamingEnumeration search(Name name,
+ Attributes matchingAttributes,
+ String[] attributesToReturn)
+ throws NamingException
+ {
+ throw new UnsupportedOperationException() ;
+ }
+
+
+ /**
+ * Searches in a single context for objects that contain a
+ * specified set of attributes, and retrieves selected attributes.
+ * See {@link #search(Name, Attributes, String[])} for details.
+ *
+ * @param name
+ * the name of the context to search
+ * @param matchingAttributes
+ * the attributes to search for
+ * @param attributesToReturn
+ * the attributes to return
+ * @return a non-null enumeration of <tt>SearchResult</tt> objects
+ * @throws NamingException if a naming exception is encountered
+ */
+ public NamingEnumeration search(String name,
+ Attributes matchingAttributes,
+ String[] attributesToReturn)
+ throws NamingException
+ {
+ throw new UnsupportedOperationException() ;
+ }
+
+
+ /**
+ * Searches in a single context for objects that contain a
+ * specified set of attributes.
+ * This method returns all the attributes of such objects.
+ * It is equivalent to supplying null as
+ * the <tt>atributesToReturn</tt> parameter to the method
+ * <code>search(Name, Attributes, String[])</code>.
+ * <br>
+ * See {@link #search(Name, Attributes, String[])} for a full description.
+ *
+ * @param name
+ * the name of the context to search
+ * @param matchingAttributes
+ * the attributes to search for
+ * @return an enumeration of <tt>SearchResult</tt> objects
+ * @throws NamingException if a naming exception is encountered
+ *
+ * @see #search(Name, Attributes, String[])
+ */
+ public NamingEnumeration search(Name name,
+ Attributes matchingAttributes)
+ throws NamingException
+ {
+ throw new UnsupportedOperationException() ;
+ }
+
+
+ /**
+ * Searches in a single context for objects that contain a
+ * specified set of attributes.
+ * See {@link #search(Name, Attributes)} for details.
+ *
+ * @param name
+ * the name of the context to search
+ * @param matchingAttributes
+ * the attributes to search for
+ * @return an enumeration of <tt>SearchResult</tt> objects
+ * @throws NamingException if a naming exception is encountered
+ */
+ public NamingEnumeration search(String name,
+ Attributes matchingAttributes)
+ throws NamingException
+ {
+ throw new UnsupportedOperationException() ;
+ }
+
+
+ /**
+ * Searches in the named context or object for entries that satisfy the
+ * given search filter. Performs the search as specified by
+ * the search controls.
+ * <p>
+ * The format and interpretation of <code>filter</code> follows RFC 2254
+ * with the
+ * following interpretations for <code>attr</code> and <code>value</code>
+ * mentioned in the RFC.
+ * <p>
+ * <code>attr</code> is the attribute's identifier.
+ * <p>
+ * <code>value</code> is the string representation the attribute's value.
+ * The translation of this string representation into the attribute's value
+ * is directory-specific.
+ * <p>
+ * For the assertion "someCount=127", for example, <code>attr</code>
+ * is "someCount" and <code>value</code> is "127".
+ * The provider determines, based on the attribute ID ("someCount")
+ * (and possibly its schema), that the attribute's value is an integer.
+ * It then parses the string "127" appropriately.
+ *<p>
+ * Any non-ASCII characters in the filter string should be
+ * represented by the appropriate Java (Unicode) characters, and
+ * not encoded as UTF-8 octets. Alternately, the
+ * "backslash-hexcode" notation described in RFC 2254 may be used.
+ *<p>
+ * If the directory does not support a string representation of
+ * some or all of its attributes, the form of <code>search</code> that
+ * accepts filter arguments in the form of Objects can be used instead.
+ * The service provider for such a directory would then translate
+ * the filter arguments to its service-specific representation
+ * for filter evaluation.
+ * See <code>search(Name, String, Object[], SearchControls)</code>.
+ * <p>
+ * RFC 2254 defines certain operators for the filter, including substring
+ * matches, equality, approximate match, greater than, less than. These
+ * operators are mapped to operators with corresponding semantics in the
+ * underlying directory. For example, for the equals operator, suppose
+ * the directory has a matching rule defining "equality" of the
+ * attributes in the filter. This rule would be used for checking
+ * equality of the attributes specified in the filter with the attributes
+ * of objects in the directory. Similarly, if the directory has a
+ * matching rule for ordering, this rule would be used for
+ * making "greater than" and "less than" comparisons.
+ *<p>
+ * Not all of the operators defined in RFC 2254 are applicable to all
+ * attributes. When an operator is not applicable, the exception
+ * <code>InvalidSearchFilterException</code> is thrown.
+ * <p>
+ * The result is returned in an enumeration of <tt>SearchResult</tt>s.
+ * Each <tt>SearchResult</tt> contains the name of the object
+ * and other information about the object (see SearchResult).
+ * The name is either relative to the target context of the search
+ * (which is named by the <code>name</code> parameter), or
+ * it is a URL string. If the target context is included in
+ * the enumeration (as is possible when
+ * <code>cons</code> specifies a search scope of
+ * <code>SearchControls.OBJECT_SCOPE</code> or
+ * <code>SearchControls.SUBSTREE_SCOPE</code>), its name is the empty
+ * string. The <tt>SearchResult</tt> may also contain attributes of the
+ * matching object if the <tt>cons</tt> argument specified that attributes
+ * be returned.
+ *<p>
+ * If the object does not have a requested attribute, that
+ * nonexistent attribute will be ignored. Those requested
+ * attributes that the object does have will be returned.
+ *<p>
+ * A directory might return more attributes than were requested
+ * (see <strong>Attribute Type Names</strong> in the class description)
+ * but is not allowed to return arbitrary, unrelated attributes.
+ *<p>
+ * See also <strong>Operational Attributes</strong> in the class
+ * description.
+ *
+ * @param name
+ * the name of the context or object to search
+ * @param filter
+ * the filter expression to use for the search; may not be null
+ * @param cons
+ * the search controls that control the search. If null,
+ * the default search controls are used (equivalent
+ * to <tt>(new SearchControls())</tt>).
+ * @return an enumeration of <tt>SearchResult</tt>s of
+ * the objects that satisfy the filter; never null
+ *
+ * @throws javax.naming.directory.InvalidSearchFilterException if the search filter specified is
+ * not supported or understood by the underlying directory
+ * @throws javax.naming.directory.InvalidSearchControlsException if the search controls
+ * contain invalid settings
+ * @throws NamingException if a naming exception is encountered
+ *
+ * @see #search(Name, String, Object[], SearchControls)
+ * @see <{SearchControls}>
+ * @see javax.naming.directory.SearchResult
+ */
+ public NamingEnumeration search(Name name,
+ String filter,
+ SearchControls cons)
+ throws NamingException
+ {
+ throw new UnsupportedOperationException() ;
+ }
+
+
+ /**
+ * Searches in the named context or object for entries that satisfy the
+ * given search filter. Performs the search as specified by
+ * the search controls.
+ * See {@link #search(Name, String, SearchControls)} for details.
+ *
+ * @param name
+ * the name of the context or object to search
+ * @param filter
+ * the filter expression to use for the search; may not be null
+ * @param cons
+ * the search controls that control the search. If null,
+ * the default search controls are used (equivalent
+ * to <tt>(new SearchControls())</tt>).
+ *
+ * @return an enumeration of <tt>SearchResult</tt>s for
+ * the objects that satisfy the filter.
+ * @throws javax.naming.directory.InvalidSearchFilterException if the search filter specified is
+ * not supported or understood by the underlying directory
+ * @throws javax.naming.directory.InvalidSearchControlsException if the search controls
+ * contain invalid settings
+ * @throws NamingException if a naming exception is encountered
+ */
+ public NamingEnumeration search(String name,
+ String filter,
+ SearchControls cons)
+ throws NamingException
+ {
+ throw new UnsupportedOperationException() ;
+ }
+
+
+ /**
+ * Searches in the named context or object for entries that satisfy the
+ * given search filter. Performs the search as specified by
+ * the search controls.
+ *<p>
+ * The interpretation of <code>filterExpr</code> is based on RFC
+ * 2254. It may additionally contain variables of the form
+ * <code>{i}</code> -- where <code>i</code> is an integer -- that
+ * refer to objects in the <code>filterArgs</code> array. The
+ * interpretation of <code>filterExpr</code> is otherwise
+ * identical to that of the <code>filter</code> parameter of the
+ * method <code>search(Name, String, SearchControls)</code>.
+ *<p>
+ * When a variable <code>{i}</code> appears in a search filter, it
+ * indicates that the filter argument <code>filterArgs[i]</code>
+ * is to be used in that place. Such variables may be used
+ * wherever an <em>attr</em>, <em>value</em>, or
+ * <em>matchingrule</em> production appears in the filter grammar
+ * of RFC 2254, section 4. When a string-valued filter argument
+ * is substituted for a variable, the filter is interpreted as if
+ * the string were given in place of the variable, with any
+ * characters having special significance within filters (such as
+ * <code>'*'</code>) having been escaped according to the rules of
+ * RFC 2254.
+ *<p>
+ * For directories that do not use a string representation for
+ * some or all of their attributes, the filter argument
+ * corresponding to an attribute value may be of a type other than
+ * String. Directories that support unstructured binary-valued
+ * attributes, for example, should accept byte arrays as filter
+ * arguments. The interpretation (if any) of filter arguments of
+ * any other type is determined by the service provider for that
+ * directory, which maps the filter operations onto operations with
+ * corresponding semantics in the underlying directory.
+ *<p>
+ * This method returns an enumeration of the results.
+ * Each element in the enumeration contains the name of the object
+ * and other information about the object (see <code>SearchResult</code>).
+ * The name is either relative to the target context of the search
+ * (which is named by the <code>name</code> parameter), or
+ * it is a URL string. If the target context is included in
+ * the enumeration (as is possible when
+ * <code>cons</code> specifies a search scope of
+ * <code>SearchControls.OBJECT_SCOPE</code> or
+ * <code>SearchControls.SUBSTREE_SCOPE</code>),
+ * its name is the empty string.
+ *<p>
+ * The <tt>SearchResult</tt> may also contain attributes of the matching
+ * object if the <tt>cons</tt> argument specifies that attributes be
+ * returned.
+ *<p>
+ * If the object does not have a requested attribute, that
+ * nonexistent attribute will be ignored. Those requested
+ * attributes that the object does have will be returned.
+ *<p>
+ * A directory might return more attributes than were requested
+ * (see <strong>Attribute Type Names</strong> in the class description)
+ * but is not allowed to return arbitrary, unrelated attributes.
+ *<p>
+ * If a search filter with invalid variable substitutions is provided
+ * to this method, the result is undefined.
+ * When changes are made to this DirContext,
+ * the effect on enumerations returned by prior calls to this method
+ * is undefined.
+ *<p>
+ * See also <strong>Operational Attributes</strong> in the class
+ * description.
+ *
+ * @param name
+ * the name of the context or object to search
+ * @param filterExpr
+ * the filter expression to use for the search.
+ * The expression may contain variables of the
+ * form "<code>{i}</code>" where <code>i</code>
+ * is a nonnegative integer. May not be null.
+ * @param filterArgs
+ * the array of arguments to substitute for the variables
+ * in <code>filterExpr</code>. The value of
+ * <code>filterArgs[i]</code> will replace each
+ * occurrence of "<code>{i}</code>".
+ * If null, equivalent to an empty array.
+ * @param cons
+ * the search controls that control the search. If null,
+ * the default search controls are used (equivalent
+ * to <tt>(new SearchControls())</tt>).
+ * @return an enumeration of <tt>SearchResult</tt>s of the objects
+ * that satisfy the filter; never null
+ *
+ * @throws ArrayIndexOutOfBoundsException if <tt>filterExpr</tt> contains
+ * <code>{i}</code> expressions where <code>i</code> is outside
+ * the bounds of the array <code>filterArgs</code>
+ * @throws javax.naming.directory.InvalidSearchControlsException if <tt>cons</tt> contains
+ * invalid settings
+ * @throws javax.naming.directory.InvalidSearchFilterException if <tt>filterExpr</tt> with
+ * <tt>filterArgs</tt> represents an invalid search filter
+ * @throws NamingException if a naming exception is encountered
+ *
+ * @see #search(Name, Attributes, String[])
+ * @see <{MessageFormat}>
+ */
+ public NamingEnumeration search(Name name,
+ String filterExpr,
+ Object[] filterArgs,
+ SearchControls cons)
+ throws NamingException
+ {
+ throw new UnsupportedOperationException() ;
+ }
+
+
+ /**
+ * Searches in the named context or object for entries that satisfy the
+ * given search filter. Performs the search as specified by
+ * the search controls.
+ * See {@link #search(Name, String, Object[], SearchControls)} for details.
+ *
+ * @param name
+ * the name of the context or object to search
+ * @param filterExpr
+ * the filter expression to use for the search.
+ * The expression may contain variables of the
+ * form "<code>{i}</code>" where <code>i</code>
+ * is a nonnegative integer. May not be null.
+ * @param filterArgs
+ * the array of arguments to substitute for the variables
+ * in <code>filterExpr</code>. The value of
+ * <code>filterArgs[i]</code> will replace each
+ * occurrence of "<code>{i}</code>".
+ * If null, equivalent to an empty array.
+ * @param cons
+ * the search controls that control the search. If null,
+ * the default search controls are used (equivalent
+ * to <tt>(new SearchControls())</tt>).
+ * @return an enumeration of <tt>SearchResult</tt>s of the objects
+ * that satisfy the filter; never null
+ *
+ * @throws ArrayIndexOutOfBoundsException if <tt>filterExpr</tt> contains
+ * <code>{i}</code> expressions where <code>i</code> is outside
+ * the bounds of the array <code>filterArgs</code>
+ * @throws javax.naming.directory.InvalidSearchControlsException if <tt>cons</tt> contains
+ * invalid settings
+ * @throws javax.naming.directory.InvalidSearchFilterException if <tt>filterExpr</tt> with
+ * <tt>filterArgs</tt> represents an invalid search filter
+ * @throws NamingException if a naming exception is encountered
+ */
+ public NamingEnumeration search(String name,
+ String filterExpr,
+ Object[] filterArgs,
+ SearchControls cons)
+ throws NamingException
+ {
+ throw new UnsupportedOperationException() ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/jndi/UnifiedLdapContext.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/jndi/UnifiedLdapContext.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,245 @@
+/*
+ * $Id: UnifiedLdapContext.java,v 1.4 2003/08/22 21:15:55 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.jndi ;
+
+
+import java.util.Hashtable ;
+
+import javax.naming.NamingException ;
+import javax.naming.ldap.Control ;
+import javax.naming.ldap.LdapContext ;
+import javax.naming.ldap.ExtendedRequest ;
+import javax.naming.ldap.ExtendedResponse ;
+
+import org.apache.eve.backend.LdapEntry ;
+
+
+/**
+ * The internal server side LdapContext implementation used to access and
+ * modify server entries. Most bind operations will be unsupported since
+ * instances of this context are already bound. This context is the main
+ * class of the internal server side provider. It is used whenever an
+ * initial context is requested within stored procedures or within a
+ * server trigger. It is also the basis for server side communication between
+ * a server host with an embedded ldapd server component. The UnifiedBackend
+ * as well as a public Kernel interface will expose a handle to the RootDSE
+ * using this LdapContext implementation.
+ *
+ * Note that the documentation used by the Java APIs for Context, DirContext
+ * and LdapContext are copied here for convenience. Eventually we can make
+ * these chunks of javadocs @see references to the respective interfaces.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.4 $
+ */
+public class UnifiedLdapContext
+ extends UnifiedDirContext
+ implements LdapContext
+{
+ UnifiedLdapContext( Hashtable an_environment )
+ {
+ super( an_environment ) ;
+ }
+
+
+ UnifiedLdapContext( Hashtable an_environment, LdapEntry a_entry )
+ throws NamingException
+ {
+ super( an_environment, a_entry ) ;
+ }
+
+
+ /////////////////////////////////
+ // LdapContext Implementations //
+ /////////////////////////////////
+
+
+ /**
+ * Performs an extended operation.
+ *
+ * This method is used to support LDAPv3 extended operations.
+ * @param request The non-null request to be performed.
+ * @return The possibly null response of the operation. null means
+ * the operation did not generate any response.
+ * @throws NamingException If an error occurred while performing the
+ * extended operation.
+ */
+ public ExtendedResponse extendedOperation(ExtendedRequest request)
+ throws NamingException
+ {
+ throw new UnsupportedOperationException() ;
+ }
+
+
+ /**
+ * Creates a new instance of this context initialized using request controls.
+ *
+ * This method is a convenience method for creating a new instance
+ * of this context for the purposes of multithreaded access.
+ * For example, if multiple threads want to use different context
+ * request controls,
+ * each thread may use this method to get its own copy of this context
+ * and set/get context request controls without having to synchronize with other
+ * threads.
+ *<p>
+ * The new context has the same environment properties and connection
+ * request controls as this context. See the class description for details.
+ * Implementations might also allow this context and the new context
+ * to share the same network connection or other resources if doing
+ * so does not impede the independence of either context.
+ *
+ * @param requestControls The possibly null request controls
+ * to use for the new context.
+ * If null, the context is initialized with no request controls.
+ *
+ * @return A non-null <tt>LdapContext</tt> instance.
+ * @exception NamingException If an error occurred while creating
+ * the new instance.
+ * @see javax.naming.ldap.InitialLdapContext
+ */
+ public LdapContext newInstance(Control[] requestControls)
+ throws NamingException
+ {
+ throw new UnsupportedOperationException() ;
+ }
+
+
+ /**
+ * Reconnects to the LDAP server using the supplied controls and
+ * this context's environment.
+ *<p>
+ * This method is a way to explicitly initiate an LDAP "bind" operation.
+ * For example, you can use this method to set request controls for
+ * the LDAP "bind" operation, or to explicitly connect to the server
+ * to get response controls returned by the LDAP "bind" operation.
+ *<p>
+ * This method sets this context's <tt>connCtls</tt>
+ * to be its new connection request controls. This context's
+ * context request controls are not affected.
+ * After this method has been invoked, any subsequent
+ * implicit reconnections will be done using <tt>connCtls</tt>.
+ * <tt>connCtls</tt> are also used as
+ * connection request controls for new context instances derived from this
+ * context.
+ * These connection request controls are not
+ * affected by <tt>setRequestControls()</tt>.
+ *<p>
+ * Service provider implementors should read the "Service Provider" section
+ * in the class description for implementation details.
+ * @param connCtls The possibly null controls to use. If null, no
+ * controls are used.
+ * @exception NamingException If an error occurred while reconnecting.
+ * @see #getConnectControls
+ * @see #newInstance
+ */
+ public void reconnect(Control[] connCtls) throws NamingException
+ {
+ throw new UnsupportedOperationException() ;
+ }
+
+
+ /**
+ * Retrieves the connection request controls in effect for this context.
+ * The controls are owned by the JNDI implementation and are
+ * immutable. Neither the array nor the controls may be modified by the
+ * caller.
+ *
+ * @return A possibly-null array of controls. null means no connect controls
+ * have been set for this context.
+ * @exception NamingException If an error occurred while getting the request
+ * controls.
+ */
+ public Control[] getConnectControls() throws NamingException
+ {
+ throw new UnsupportedOperationException() ;
+ }
+
+
+ /**
+ * Sets the request controls for methods subsequently
+ * invoked on this context.
+ * The request controls are owned by the JNDI implementation and are
+ * immutable. Neither the array nor the controls may be modified by the
+ * caller.
+ * <p>
+ * This removes any previous request controls and adds
+ * <tt>requestControls</tt>
+ * for use by subsequent methods invoked on this context.
+ * This method does not affect this context's connection request controls.
+ *<p>
+ * Note that <tt>requestControls</tt> will be in effect until the next
+ * invocation of <tt>setRequestControls()</tt>. You need to explicitly
+ * invoke <tt>setRequestControls()</tt> with <tt>null</tt> or an empty
+ * array to clear the controls if you don't want them to affect the
+ * context methods any more.
+ * To check what request controls are in effect for this context, use
+ * <tt>getRequestControls()</tt>.
+ * @param requestControls The possibly null controls to use. If null, no
+ * controls are used.
+ * @exception NamingException If an error occurred while setting the
+ * request controls.
+ * @see #getRequestControls
+ */
+ public void setRequestControls(Control[] requestControls)
+ throws NamingException
+ {
+ throw new UnsupportedOperationException() ;
+ }
+
+
+ /**
+ * Retrieves the request controls in effect for this context.
+ * The request controls are owned by the JNDI implementation and are
+ * immutable. Neither the array nor the controls may be modified by the
+ * caller.
+ *
+ * @return A possibly-null array of controls. null means no request controls
+ * have been set for this context.
+ * @exception NamingException If an error occurred while getting the request
+ * controls.
+ * @see #setRequestControls
+ */
+ public Control[] getRequestControls() throws NamingException
+ {
+ throw new UnsupportedOperationException() ;
+ }
+
+
+ /**
+ * Retrieves the response controls produced as a result of the last
+ * method invoked on this context.
+ * The response controls are owned by the JNDI implementation and are
+ * immutable. Neither the array nor the controls may be modified by the
+ * caller.
+ *<p>
+ * These response controls might have been generated by a successful or
+ * failed operation.
+ *<p>
+ * When a context method that may return response controls is invoked,
+ * response controls from the previous method invocation are cleared.
+ * <tt>getResponseControls()</tt> returns all of the response controls
+ * generated by LDAP operations used by the context method in the order
+ * received from the LDAP server.
+ * Invoking <tt>getResponseControls()</tt> does not
+ * clear the response controls. You can call it many times (and get
+ * back the same controls) until the next context method that may return
+ * controls is invoked.
+ *<p>
+ * @return A possibly null array of controls. If null, the previous
+ * method invoked on this context did not produce any controls.
+ * @exception NamingException If an error occurred while getting the response
+ * controls.
+ */
+ public Control[] getResponseControls() throws NamingException
+ {
+ throw new UnsupportedOperationException() ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/listener/ListenerException.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/listener/ListenerException.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,38 @@
+/*
+ * $Id: ListenerException.java,v 1.3 2003/03/13 18:27:38 akarasulu Exp $
+ * $Prologue$
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.listener ;
+
+
+import org.apache.avalon.framework.CascadingRuntimeException ;
+
+
+/** This exception is thrown when protocol errors occurred */
+public class ListenerException extends CascadingRuntimeException
+{
+ /**
+ * Constructs an Exception with a detailed message.
+ * @param Message The message associated with the exception.
+ */
+ public ListenerException(String message, Throwable t)
+ {
+ super(message, t) ;
+ }
+
+
+ /**
+ * Constructs an Exception with a detailed message.
+ * @param Message The message associated with the exception.
+ */
+ public ListenerException(String message)
+ {
+ super(message, null) ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/listener/ListenerModule.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/listener/ListenerModule.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,298 @@
+/*
+ * $Id: ListenerModule.java,v 1.5 2003/03/13 18:27:38 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.listener ;
+
+
+import java.io.IOException ;
+
+import java.net.Socket ;
+import java.net.InetAddress ;
+import java.net.ServerSocket ;
+import java.net.UnknownHostException ;
+
+import java.io.IOException ;
+
+import java.net.Socket ;
+import java.net.InetAddress ;
+import java.net.ServerSocket ;
+import java.net.UnknownHostException ;
+
+import org.apache.eve.AbstractModule ;
+import org.apache.eve.event.ConnectEvent ;
+import org.apache.eve.client.ClientManager ;
+
+import org.apache.avalon.framework.service.ServiceManager ;
+import org.apache.avalon.framework.service.ServiceException ;
+import org.apache.avalon.framework.configuration.Configuration ;
+import org.apache.avalon.cornerstone.services.threads.ThreadManager ;
+import org.apache.avalon.framework.configuration.ConfigurationException ;
+
+
+/**
+ * A server listener module represents a single server socket bound listening
+ * for client connections on a tcp port off an interface. This implementation
+ * is rather primitive in that only one server socket is used for the entire
+ * module. In the near future expect the implementation to support multiple
+ * server sockets and to optionally sepecify whether SSL is used.
+ *
+ * @phoenix:block
+ * @phoenix:mx-topic name="ListenerModule"
+ * @phoenix:service name="org.apache.eve.listener.ServerListener"
+ */
+public class ListenerModule
+ extends AbstractModule
+ implements ServerListener, Runnable
+{
+ /** config.xml tag name for port number to listen to */
+ public static final String PORT_TAG = "port" ;
+ /** config.xml tag name for the ip interface (or hostname) to listen on */
+ public static final String HOST_TAG = "host" ;
+ /** config.xml tag name for the server socket connection backlog */
+ public static final String BACKLOG_TAG = "backlog" ;
+
+ /** default tcp port to listen on (389) */
+ public static final int DEFAULT_PORT = 389 ;
+ /** default server socket backlog (50) */
+ public static final int DEFAULT_BACKLOG = 50 ;
+ /** default interface to listen on (localhost) */
+ public static final String DEFAULT_HOST = "localhost" ;
+
+ /** tcp port value set by reading config.xml */
+ private int m_port ;
+ /** server socket backlog value set by reading config.xml */
+ private int m_backlog ;
+ /** inet address to listen on set by reading config.xml */
+ private InetAddress m_address ;
+ /** ldap url composed by using port and host values */
+ private String m_ldapUrl = null ;
+ /** handle on the client manager service */
+ private ClientManager m_clientManager = null ;
+ /** server socket used to listen for incomming connections */
+ private ServerSocket m_serverSocket = null ;
+
+
+ ////////////////////////
+ // Some MBean Methods //
+ ////////////////////////
+
+
+ /**
+ * Gets the tcp port this listener listens to for client connections.
+ *
+ * @phoenix:mx-attribute
+ * @phoenix:mx-description gets the tcp port listened to.
+ * @phoenix:mx-isWriteable no
+ */
+ public int getPort()
+ {
+ return m_port ;
+ }
+
+
+ /**
+ * Gets the ip interface listened to for client connections as an address
+ *
+ * @phoenix:mx-attribute
+ * @phoenix:mx-description gets the ip address listened to.
+ * @phoenix:mx-isWriteable no
+ */
+ public String getAddress()
+ {
+ return m_address.getHostAddress() ;
+ }
+
+
+ /**
+ * Gets the effect ldap url of this listener using the port and address
+ *
+ * @phoenix:mx-attribute
+ * @phoenix:mx-description gets the ldapd URL of this listener
+ * @phoenix:mx-isWriteable no
+ */
+ public String getLdapURL()
+ {
+ return m_ldapUrl ;
+ }
+
+
+ /**
+ * Gets the maximum possible number of client connections backlogged on this
+ * listener's server socket before rejecting client connections.
+ *
+ * @phoenix:mx-attribute
+ * @phoenix:mx-description gets the server socket backlog
+ * @phoenix:mx-isWriteable no
+ */
+ public int getBacklog()
+ {
+ return m_backlog ;
+ }
+
+
+ ////////////////////////
+ // Life-Cycle Methods //
+ ////////////////////////
+
+
+ /**
+ * Runnable implementation which runs in a loop until this module is
+ * stopped. The loop waits blocked for client connections to come in via
+ * the accept socket call on the server socket. Once a connection comes in
+ * a ConnectEvent is created containing the client socket returned from the
+ * accept call. The event is then enqueued onto the event queue of the
+ * client manager stage using the connectPerformed method on the
+ * ClientManager. Once the event is enqueued the loop sits waiting for the
+ * next client connection.
+ */
+ public void run()
+ {
+ if(getLogger().isDebugEnabled()) {
+ getLogger().debug("Listening for LDAP clients at " + m_ldapUrl) ;
+ }
+
+
+ while(hasStarted()) {
+ try {
+ Socket l_clientSocket = m_serverSocket.accept() ;
+
+ if(getLogger().isDebugEnabled()) {
+ getLogger().debug("Client connected from " +
+ l_clientSocket.getInetAddress()) ;
+ }
+
+ ConnectEvent l_event = new ConnectEvent(l_clientSocket) ;
+ m_clientManager.connectPerformed(l_event) ;
+ } catch(IOException e) {
+ getLogger().error("IO failure on accept(): ", e) ;
+ throw new ListenerException("IO failure on accept(): ", e) ;
+ }
+ }
+ }
+
+
+ /**
+ * Module lifecycle method that calls <code> super.start() </code> first
+ * then creates a new thread using this Runnable Module. The thread is
+ * then started.
+ *
+ * @throws Exception if superclass <code>start()</code> call fails or this
+ * Module's thread <code>start()</code> call fails.
+ */
+ public void start()
+ throws Exception
+ {
+ super.start() ;
+ new Thread(this).start() ;
+ }
+
+
+ /**
+ * Initializes this module by creating and binding the server socket.
+ *
+ * @throws Exception if the bind fails for any reason.
+ */
+ public void initialize()
+ throws Exception
+ {
+ try {
+ m_serverSocket = new ServerSocket(m_port, m_backlog, m_address) ;
+ } catch(IOException e) {
+ getLogger().error("Error on bind: " + e) ;
+ throw e ;
+ }
+ }
+
+
+ /*
+ <pre>
+ E X A M P L E C O N F I G U R A T I O N
+ <listener>
+ <port>389</port>
+ <host>localhost</host>
+ <backlog>50</backlog>
+ </listener>
+ </pre>
+ */
+ public void configure(Configuration a_config)
+ throws ConfigurationException
+ {
+ String l_host = a_config.getChild(HOST_TAG).getValue(DEFAULT_HOST) ;
+ m_port = a_config.getChild(PORT_TAG).getValueAsInteger(DEFAULT_PORT) ;
+ m_backlog =
+ a_config.getChild(BACKLOG_TAG).getValueAsInteger(DEFAULT_BACKLOG) ;
+
+ try {
+ m_address = InetAddress.getByName(l_host) ;
+ } catch(UnknownHostException e) {
+ throw new ConfigurationException("Could not resolve host " +
+ l_host, e) ;
+ }
+
+ m_ldapUrl = "ldap://" + l_host + ":" + m_port ;
+ if(getLogger().isDebugEnabled()) {
+ getLogger().debug("Configured to listen on port "+ m_port
+ + " with host address " + m_address) ;
+ }
+ }
+
+
+ /**
+ * Extracts a handle on the system ClientManager from the ServiceManager.
+ *
+ * @phoenix:dependency name="org.apache.eve.client.ClientManager"
+ */
+ public void service(ServiceManager a_manager)
+ throws ServiceException
+ {
+ m_clientManager = (ClientManager) a_manager.lookup(ClientManager.ROLE) ;
+ }
+
+
+ /**
+ * Gets this Module implementation's service interface (a.k.a its role)
+ *
+ * @return the service interface name
+ * @phoenix:mx-attribute
+ * @phoenix:mx-description gets the service interface (ROLE)
+ * @phoenix:mx-isWriteable no
+ */
+ public String getImplementationRole()
+ {
+ return ROLE ;
+ }
+
+
+ /**
+ * Gets this Module implementation's descriptive name.
+ *
+ * @return descriptive module name
+ * @phoenix:mx-attribute
+ * @phoenix:mx-description gets the descriptive name
+ * @phoenix:mx-isWriteable no
+ */
+ public String getImplementationName()
+ {
+ return "Server Socket Listener Module" ;
+ }
+
+
+ /**
+ * Gets this Module implementation's fully qualified class name.
+ *
+ * @return the fqcn
+ * @phoenix:mx-attribute
+ * @phoenix:mx-description gets the FQCN
+ * @phoenix:mx-isWriteable no
+ */
+ public String getImplementationClassName()
+ {
+ return this.getClass().getName() ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/listener/ServerListener.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/listener/ServerListener.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,58 @@
+/*
+ * $Id: ServerListener.java,v 1.4 2003/03/13 18:27:39 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.listener ;
+
+
+
+import org.apache.eve.event.ConnectListener ;
+
+
+/**
+ * The ServiceListener service interface is implemented by server socket
+ * listner modules in the LDAPd server. It currently is designed to only
+ * support one server socket. Expect this interface to change in the near
+ * future to accomodate multiple socket listeners and SSL enabled server
+ * sockets.
+ */
+public interface ServerListener
+{
+ /** role of this service interface */
+ public static final String ROLE = ServerListener.class.getName() ;
+
+ /**
+ * Gets the server socket backlog for this ServerListener
+ *
+ * @return client connection backlog
+ */
+ public int getBacklog() ;
+
+ /**
+ * Gets the TCP port number this ServerListener listens on.
+ *
+ * @return the tcp port number
+ */
+ public int getPort() ;
+
+ /**
+ * Gets the ip interface address this ServerListener listens on.
+ *
+ * @return the ip address octets as a String i.e. 127.0.0.1
+ */
+ public String getAddress() ;
+
+ /**
+ * Gets the LDAP URL for this ServerListener using the specified ip address
+ * and the tcp port number listened to. The ipaddress is resolved to a host
+ * name.
+ *
+ * @return the LDAP URL like so ldap://localhost:389
+ */
+ public String getLdapURL() ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/output/OutputManager.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/output/OutputManager.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,34 @@
+/*
+ * $Id: OutputManager.java,v 1.4 2003/03/13 18:27:41 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.output ;
+
+
+import java.io.OutputStream ;
+import org.apache.eve.client.ClientKey ;
+import org.apache.eve.event.OutputListener;
+import org.apache.eve.client.ClientManagerSlave;
+import java.io.InputStream;
+import java.io.IOException;
+
+
+public interface OutputManager
+ extends OutputListener, ClientManagerSlave
+{
+ public static final String ROLE = OutputManager.class.getName() ;
+
+ /**
+ * Synchronous write which reads from the InputStream argument writing
+ * it to the client's OutputStream.
+ */
+ public void write(ClientKey a_clientKey, InputStream an_in)
+ throws IOException ;
+ void register(ClientKey a_clientKey, OutputStream l_clientOut) ;
+ void unregister(ClientKey a_clientKey) ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/output/OutputModule.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/output/OutputModule.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,208 @@
+/*
+ * $Id: OutputModule.java,v 1.10 2003/04/21 19:13:51 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.output ;
+
+
+import org.apache.eve.seda.AbstractStage ;
+import org.apache.eve.client.ClientKey;
+import java.io.OutputStream;
+import org.apache.eve.event.OutputEvent;
+import java.util.HashMap;
+import java.util.Map;
+import java.io.InputStream;
+import java.io.IOException;
+import org.apache.eve.event.AbstractEventHandler;
+import org.apache.eve.client.ClientManager;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.logger.Logger;
+import java.util.EventObject;
+import org.apache.eve.client.KeyExpiryException;
+import java.io.BufferedOutputStream;
+
+/**
+ * @phoenix:block
+ * @phoenix:service name="org.apache.eve.output.OutputManager"
+ */
+public class OutputModule
+ extends AbstractStage
+ implements OutputManager
+{
+ private Map m_streams = new HashMap() ;
+ private ClientManager m_clientManager = null ;
+
+
+ public OutputModule()
+ {
+ m_handler = new OutputEventHandler() ;
+ }
+
+
+ class OutputEventHandler extends AbstractEventHandler
+ {
+ public void handleEvent(EventObject an_event)
+ {
+ if(an_event instanceof OutputEvent) {
+ OutputEvent l_event = (OutputEvent) an_event ;
+ ClientKey l_clientKey = l_event.getClientKey() ;
+
+ try {
+ write(l_clientKey, l_event.getInputStream()) ;
+ } catch(IOException e) {
+ getLogger().error("Abruptly dropping client "
+ + l_clientKey + ": ", e) ;
+ m_clientManager.drop(l_clientKey) ;
+ }
+ }
+ }
+ }
+
+
+ public void register( ClientKey a_clientKey, OutputStream l_clientOut )
+ {
+ synchronized( m_streams )
+ {
+ m_streams.put( a_clientKey, l_clientOut ) ;
+ }
+ }
+
+
+ public void unregister( ClientKey a_clientKey )
+ {
+ synchronized( m_streams )
+ {
+ m_streams.remove( a_clientKey ) ;
+ }
+ }
+
+
+ public void registerClientManager(ClientManager a_manager)
+ {
+ m_clientManager = a_manager ;
+ }
+
+
+ public void writeResponse(OutputEvent an_event)
+ {
+ enqueue(an_event) ;
+ }
+
+
+ public void write(ClientKey a_clientKey, InputStream an_in)
+ throws IOException
+ {
+ Object l_lock = null ;
+ OutputStream l_out = null ;
+
+ synchronized( m_streams )
+ {
+ l_out = new BufferedOutputStream((OutputStream)
+ m_streams.get(a_clientKey)) ;
+ }
+
+ if(null == l_out) {
+ getLogger().error("Write to client " + a_clientKey +
+ " aborted: client output stream not registered!") ;
+ return ;
+ }
+
+ if(getLogger().isDebugEnabled()) {
+ getLogger().debug("Output stream lookup succeeded for client: "
+ + a_clientKey) ;
+ getLogger().debug("About to lock on client " + a_clientKey
+ + " outputLock") ;
+ }
+
+ // Obtain output lock for write to client.
+ try {
+ l_lock = a_clientKey.getOutputLock() ;
+ } catch(KeyExpiryException e) {
+ // Log inability to deliver response to disconnected client and exit
+ if(getLogger().isInfoEnabled()) {
+ getLogger().info("Client " + a_clientKey
+ + " disconnected or was dropped before response delivery") ;
+ }
+ return ;
+ }
+
+ // Synchronize on client output stream lock object.
+ synchronized(l_lock) {
+ if(getLogger().isDebugEnabled()) {
+ getLogger().debug("Successfully locked on socket "
+ + "output stream - writing to client: " + a_clientKey) ;
+ }
+
+ //
+ // Cycle writes to output stream while the client is connected and
+ // the response content input stream still has data to read from.
+ // Use 512 byte buffer since buffered output stream by default uses
+ // a 512 byte buffer.
+ //
+
+ byte [] l_buf = new byte[512] ;
+ int l_length = -1 ;
+ while(!a_clientKey.hasExpired() &&
+ ((l_length = an_in.read(l_buf)) != -1))
+ {
+ l_out.write(l_buf, 0, l_length) ;
+ }
+
+ l_out.flush() ;
+ l_lock.notifyAll() ;
+ }
+
+ if(getLogger().isDebugEnabled()) {
+ getLogger().debug("Write to client " + a_clientKey +
+ " socket output stream complete - PDU delivered!") ;
+ }
+ }
+
+
+ /////////////////////////////////
+ // Module & Life-Cycle Methods //
+ /////////////////////////////////
+
+
+ public void enableLogging(Logger a_logger)
+ {
+ super.enableLogging(a_logger) ;
+ m_handler.enableLogging(a_logger) ;
+ }
+
+
+ public String getImplementationRole()
+ {
+ return ROLE ;
+ }
+
+
+ public String getImplementationName()
+ {
+ return "Client Output Manager Module" ;
+ }
+
+
+ public String getImplementationClassName()
+ {
+ return this.getClass().getName() ;
+ }
+
+
+ /**
+ * Needed for the javadoclet!
+ *
+ * @phoenix:dependency name="org.apache.avalon.cornerstone.services.threads.ThreadManager"
+ */
+ public void service(ServiceManager a_manager)
+ throws ServiceException
+ {
+ super.service(a_manager) ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/AbandonHandler.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/AbandonHandler.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,97 @@
+/*
+ * $Id: AbandonHandler.java,v 1.2 2003/08/22 21:15:55 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.protocol ;
+
+
+import java.math.BigInteger ;
+
+import org.apache.ldap.common.message.Request ;
+import org.apache.ldap.common.message.AbandonRequest ;
+import org.apache.ldap.common.message.MessageTypeEnum ;
+import org.apache.ldap.common.NotImplementedException ;
+
+
+/**
+ * Handles the processing of AbandonRequests. Not presently implemented.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.2 $
+ */
+public final class AbandonHandler
+ implements NoReplyHandler
+{
+ /** Reference to the protocol module this handler is part of */
+ private final ProtocolModule m_module ;
+
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Creates a handler for AbandonRequests to work on behalf of a
+ * ProtocolModule.
+ *
+ * @param a_module the ProtocolModule this handler is part of.
+ */
+ public AbandonHandler( ProtocolModule a_module )
+ {
+ m_module = a_module ;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // RequestHandler Interface Method Implementations
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Gets the handler type enumeration constant associated with this handler.
+ *
+ * @return HandlerTypeEnum.NOREPLY
+ */
+ public final HandlerTypeEnum getHandlerType()
+ {
+ return HandlerTypeEnum.NOREPLY ;
+ }
+
+
+ /**
+ * Gets the message type enumeration constant associated with this handler.
+ *
+ * @return HandlerTypeEnum.NOREPLY
+ */
+ public final MessageTypeEnum getRequestType()
+ {
+ return MessageTypeEnum.ABANDONREQUEST ;
+ }
+
+
+ /**
+ * Handles an AbandonRequest by stopping the outstanding request specified.
+ *
+ * @param a_request the AbandonRequest to handle.
+ * @throws ClassCastException if the a_request argument is not an
+ * AbandonRequest.
+ */
+ public final void handle( Request a_request )
+ {
+ try
+ {
+ throw new NotImplementedException( "Handler not complete!" ) ;
+ }
+ catch( Throwable t )
+ {
+ m_module.getLogger().error( "Failed on AbandonRequest!", t ) ;
+ }
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/AddHandler.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/AddHandler.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,137 @@
+/*
+ * $Id: AddHandler.java,v 1.2 2003/08/22 21:15:55 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.protocol ;
+
+
+import javax.naming.Name ;
+import javax.naming.ldap.LdapContext ;
+import javax.naming.directory.Attributes ;
+
+import org.apache.ldap.common.message.AddRequest ;
+import org.apache.ldap.common.message.AddResponse ;
+import org.apache.ldap.common.message.ResultResponse ;
+import org.apache.ldap.common.message.MessageTypeEnum ;
+import org.apache.ldap.common.message.AddResponseImpl ;
+import org.apache.ldap.common.message.SingleReplyRequest ;
+
+
+
+/**
+ * AddRequest handler for add protocol requests.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.2 $
+ */
+public class AddHandler
+ implements SingleReplyHandler
+{
+ /** The protocol module this request handler is part of */
+ private final ProtocolModule m_module ;
+
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Creates a AddRequest protocol data unit handler.
+ *
+ * @param a_module the module this handler is associated with.
+ */
+ public AddHandler( ProtocolModule a_module )
+ {
+ m_module = a_module ;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // RequestHandler Interface Method Implementations
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Gets the handler type.
+ *
+ * @return a HandlerTypeEnum constant.
+ */
+ public HandlerTypeEnum getHandlerType()
+ {
+ return HandlerTypeEnum.SINGLEREPLY ;
+ }
+
+
+ /**
+ * Gets the request message type handled by this handler.
+ *
+ * @return a MessageTypeEnum constant associated with the request message.
+ */
+ public MessageTypeEnum getRequestType()
+ {
+ return MessageTypeEnum.ADDREQUEST ;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // RequestHandler Interface Method Implementations
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Gets the response message type for this SingleReplyHandler.
+ *
+ * @return the MessageTypeEnum constant associated with this handler.
+ */
+ public MessageTypeEnum getResponseType()
+ {
+ return MessageTypeEnum.ADDRESPONSE ;
+ }
+
+
+ /**
+ * Handles a request that generates a sole response by returning the
+ * response object back to the caller.
+ *
+ * @param a_request the request to handle.
+ * @return the response to the request argument.
+ * @throws ClassCastException if a_request is not a AddRequest
+ */
+ public ResultResponse handle( SingleReplyRequest a_request )
+ {
+ Name l_dn = null ;
+ AddRequest l_request = ( AddRequest ) a_request ;
+ AddResponse l_response =
+ new AddResponseImpl( a_request.getMessageId() ) ;
+ Attributes l_attributes = l_request.getEntry() ;
+
+ try
+ {
+ l_dn = m_module.getName( l_request.getName() ) ;
+
+ // Get the context to the parent and create new subcontext for
+ // the entry we are currently adding.
+ LdapContext l_parent = ( LdapContext )
+ m_module.getContext( l_dn.getPrefix( l_dn.size() - 1 ) ) ;
+ l_parent.createSubcontext( l_dn.get( l_dn.size()-1 ),
+ l_attributes ) ;
+
+ // Set response result to success
+ m_module.setResult( l_response, l_dn ) ;
+ }
+ catch( Throwable t )
+ {
+ // Set response result to error code based on the error.
+ m_module.setResult( l_response, l_dn, t ) ;
+ }
+
+ return l_response ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/BindHandler.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/BindHandler.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,201 @@
+/*
+ * $Id: BindHandler.java,v 1.2 2003/08/22 21:15:56 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.protocol ;
+
+
+import javax.naming.Name ;
+import javax.naming.NamingException ;
+import javax.naming.InvalidNameException ;
+import javax.naming.NameNotFoundException ;
+
+import org.apache.ldap.common.message.BindRequest ;
+import org.apache.ldap.common.message.BindResponse ;
+import org.apache.ldap.common.message.ResultCodeEnum ;
+import org.apache.ldap.common.message.ResultResponse ;
+import org.apache.ldap.common.message.MessageTypeEnum ;
+import org.apache.ldap.common.message.BindResponseImpl ;
+import org.apache.ldap.common.message.SingleReplyRequest ;
+
+import org.apache.eve.client.ClientKey ;
+import org.apache.eve.client.ClientManager ;
+import org.apache.eve.security.LdapPrincipal ;
+import org.apache.eve.backend.BackendException ;
+import org.apache.eve.security.auth.AuthenticationManager ;
+import org.apache.eve.security.auth.AuthenticationException ;
+
+
+/**
+ * BindRequest handler for bind protocol requests.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.2 $
+ */
+public class BindHandler
+ implements SingleReplyHandler
+{
+ /** The protocol module this request handler is part of */
+ private final ProtocolModule m_module ;
+
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Creates a BindRequest protocol data unit handler.
+ *
+ * @param a_module the module this handler is associated with.
+ */
+ public BindHandler( ProtocolModule a_module )
+ {
+ m_module = a_module ;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // RequestHandler Interface Method Implementations
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Gets the handler type.
+ *
+ * @return a HandlerTypeEnum constant.
+ */
+ public HandlerTypeEnum getHandlerType()
+ {
+ return HandlerTypeEnum.SINGLEREPLY ;
+ }
+
+
+ /**
+ * Gets the request message type handled by this handler.
+ *
+ * @return a MessageTypeEnum constant associated with the request message.
+ */
+ public MessageTypeEnum getRequestType()
+ {
+ return MessageTypeEnum.BINDREQUEST ;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // RequestHandler Interface Method Implementations
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Gets the response message type for this SingleReplyHandler.
+ *
+ * @return the MessageTypeEnum constant associated with this handler.
+ */
+ public MessageTypeEnum getResponseType()
+ {
+ return MessageTypeEnum.BINDRESPONSE ;
+ }
+
+
+ /**
+ * Handles a request that generates a sole response by returning the
+ * response object back to the caller.
+ *
+ * @param a_request the request to handle.
+ * @return the response to the request argument.
+ * @throws ClassCastException if a_request is not a BindRequest
+ */
+ public ResultResponse handle( SingleReplyRequest a_request )
+ {
+ Name l_dn = null ;
+ BindRequest l_request = ( BindRequest ) a_request ;
+
+ // Prepare the response wrapper ahead of time.
+ BindResponse l_response =
+ new BindResponseImpl( l_request.getMessageId() ) ;
+
+ try
+ {
+ l_dn = m_module.getName( l_request.getName() ) ;
+ }
+ // Respond to the user with an INVALIDDNSYNTAX error response
+ catch( NamingException ne )
+ {
+ String l_msg = "'" + l_request.getName() + "' for the bind"
+ + " user's DN does not conform to the DN syntax." ;
+ m_module.setResult( l_response, ResultCodeEnum.INVALIDDNSYNTAX,
+ l_msg, ne ) ;
+ return l_response ;
+ }
+
+ // Check if unsupported SASL mechanisms are being used. Use of
+ // SASL mechanisms result in a AUTHMETHODNOTSUPPORTED error.
+ if( ! l_request.isSimple() )
+ {
+ m_module.setResult( l_response,
+ ResultCodeEnum.AUTHMETHODNOTSUPPORTED, l_dn,
+ "SASL based authentication methods not supported!", null ) ;
+ return l_response ;
+ }
+
+ // Perform simple authentication using the authentication manager
+ try
+ {
+ AuthenticationManager l_am = m_module.getAuthenticationManager() ;
+ LdapPrincipal l_principal = l_am.loginSimple( l_dn,
+ new String( l_request.getCredentials() ) ) ;
+ ClientManager l_cm = m_module.getClientManager() ;
+ ClientKey l_clientKey = l_cm.getClientSession().getClientKey() ;
+ l_cm.setUserPrincipal( l_clientKey, l_principal ) ;
+ m_module.setResult( l_response, l_dn ) ;
+ }
+ catch( InvalidNameException ine )
+ {
+ String l_msg = "InvalidNameException should never be thrown by the "
+ + "AuthenticationManager since we have already verified a "
+ + "correct Dn syntax." ;
+ m_module.setResult( l_response, ResultCodeEnum.INVALIDDNSYNTAX,
+ l_dn, l_msg, ine ) ;
+ }
+ catch( NameNotFoundException nnfe )
+ {
+ String l_msg = "NameNotFoundException should never be thrown by the"
+ + " AuthenticationManager since we have already verified the "
+ + "exsitiance of the entry '" + l_request.getName() + "'" ;
+ m_module.setResult( l_response, ResultCodeEnum.NOSUCHOBJECT, l_dn,
+ l_msg, nnfe ) ;
+ }
+ catch( NamingException ne )
+ {
+ m_module.setResult( l_response, l_dn, ne ) ;
+ }
+ catch( BackendException be )
+ {
+ m_module.setResult( l_response, l_dn, be ) ;
+ }
+ catch( AuthenticationException ae )
+ {
+ String l_msg = "'" + l_request.getName() + "' is either not the "
+ + "correct username associated with the supplied password." ;
+ m_module.setResult( l_response, ResultCodeEnum.INVALIDCREDENTIALS,
+ l_dn, l_msg, ae ) ;
+ }
+ catch( IllegalArgumentException iae )
+ {
+ String l_msg = "No backend for the namespace associated with '"
+ + l_request.getName() + "' exists. Check your backend "
+ + "configuration to determine the suffix to use." ;
+ m_module.setResult( l_response, ResultCodeEnum.NOSUCHOBJECT,
+ l_dn, l_msg, iae ) ;
+ }
+
+ return l_response ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/CompareHandler.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/CompareHandler.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,106 @@
+/*
+ * $Id: CompareHandler.java,v 1.2 2003/08/22 21:15:56 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.protocol ;
+
+
+import org.apache.ldap.common.message.ResultResponse ;
+import org.apache.ldap.common.message.CompareRequest ;
+import org.apache.ldap.common.message.MessageTypeEnum ;
+import org.apache.ldap.common.NotImplementedException ;
+import org.apache.ldap.common.message.SingleReplyRequest ;
+
+
+/**
+ * CompareRequest handler for compare protocol requests.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.2 $
+ */
+public class CompareHandler
+ implements SingleReplyHandler
+{
+ /** The protocol module this request handler is part of */
+ private final ProtocolModule m_module ;
+
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Creates a CompareRequest protocol data unit handler.
+ *
+ * @param a_module the module this handler is associated with.
+ */
+ public CompareHandler( ProtocolModule a_module )
+ {
+ m_module = a_module ;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // RequestHandler Interface Method Implementations
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Gets the handler type.
+ *
+ * @return a HandlerTypeEnum constant.
+ */
+ public HandlerTypeEnum getHandlerType()
+ {
+ return HandlerTypeEnum.SINGLEREPLY ;
+ }
+
+
+ /**
+ * Gets the request message type handled by this handler.
+ *
+ * @return a MessageTypeEnum constant associated with the request message.
+ */
+ public MessageTypeEnum getRequestType()
+ {
+ return MessageTypeEnum.COMPAREREQUEST ;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // RequestHandler Interface Method Implementations
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Gets the response message type for this SingleReplyHandler.
+ *
+ * @return the MessageTypeEnum constant associated with this handler.
+ */
+ public MessageTypeEnum getResponseType()
+ {
+ return MessageTypeEnum.COMPARERESPONSE ;
+ }
+
+
+ /**
+ * Handles a request that generates a sole response by returning the
+ * response object back to the caller.
+ *
+ * @param a_request the request to handle.
+ * @return the response to the request argument.
+ * @throws ClassCastException if a_request is not a CompareRequest
+ */
+ public ResultResponse handle( SingleReplyRequest a_request )
+ {
+ CompareRequest l_request = ( CompareRequest ) a_request ;
+ throw new NotImplementedException() ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/DeleteHandler.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/DeleteHandler.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,125 @@
+/*
+ * $Id: DeleteHandler.java,v 1.2 2003/08/22 21:15:56 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.protocol ;
+
+
+import org.apache.ldap.common.message.DeleteRequest ;
+import org.apache.ldap.common.message.ResultResponse ;
+import org.apache.ldap.common.message.MessageTypeEnum ;
+import org.apache.ldap.common.message.SingleReplyRequest ;
+import org.apache.ldap.common.message.DeleteResponse;
+import org.apache.ldap.common.message.DeleteResponseImpl;
+import javax.naming.NamingException;
+import javax.naming.InitialContext;
+
+
+/**
+ * DeleteRequest handler for delete protocol requests.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.2 $
+ */
+public class DeleteHandler
+ implements SingleReplyHandler
+{
+ /** The protocol module this request handler is part of */
+ private final ProtocolModule m_module ;
+
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Creates a DeleteRequest protocol data unit handler.
+ *
+ * @param a_module the module this handler is associated with.
+ */
+ public DeleteHandler( ProtocolModule a_module )
+ {
+ m_module = a_module ;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // RequestHandler Interface Method Implementations
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Gets the handler type.
+ *
+ * @return a HandlerTypeEnum constant.
+ */
+ public HandlerTypeEnum getHandlerType()
+ {
+ return HandlerTypeEnum.SINGLEREPLY ;
+ }
+
+
+ /**
+ * Gets the request message type handled by this handler.
+ *
+ * @return a MessageTypeEnum constant associated with the request message.
+ */
+ public MessageTypeEnum getRequestType()
+ {
+ return MessageTypeEnum.DELREQUEST ;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // RequestHandler Interface Method Implementations
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Gets the response message type for this SingleReplyHandler.
+ *
+ * @return the MessageTypeEnum constant associated with this handler.
+ */
+ public MessageTypeEnum getResponseType()
+ {
+ return MessageTypeEnum.DELRESPONSE ;
+ }
+
+
+ /**
+ * Handles a request that generates a sole response by returning the
+ * response object back to the caller.
+ *
+ * @param a_request the request to handle.
+ * @return the response to the request argument.
+ * @throws ClassCastException if a_request is not a DeleteRequest
+ */
+ public ResultResponse handle( SingleReplyRequest a_request )
+ {
+ InitialContext l_initCtx ;
+ DeleteRequest l_request = ( DeleteRequest ) a_request ;
+ DeleteResponse l_response =
+ new DeleteResponseImpl( l_request.getMessageId() ) ;
+
+ try
+ {
+ l_initCtx = Utils.getInitialContext() ;
+ l_initCtx.destroySubcontext( l_request.getName() ) ;
+ Utils.setResult( l_response, l_request.getName(), false ) ;
+ }
+ // Could be anything here.
+ catch( NamingException ne )
+ {
+ Utils.setResult( l_response, l_request.getName(), ne ) ;
+ }
+
+ return l_response ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/ExtendedHandler.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/ExtendedHandler.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,106 @@
+/*
+ * $Id: ExtendedHandler.java,v 1.2 2003/08/22 21:15:56 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.protocol ;
+
+
+import org.apache.ldap.common.message.AddRequest ;
+import org.apache.ldap.common.message.ResultResponse ;
+import org.apache.ldap.common.message.MessageTypeEnum ;
+import org.apache.ldap.common.NotImplementedException ;
+import org.apache.ldap.common.message.SingleReplyRequest ;
+
+
+/**
+ * ExtendedRequest handler for extended protocol requests.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.2 $
+ */
+public class ExtendedHandler
+ implements SingleReplyHandler
+{
+ /** The protocol module this request handler is part of */
+ private final ProtocolModule m_module ;
+
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Creates a ExtendedRequest protocol data unit handler.
+ *
+ * @param a_module the module this handler is associated with.
+ */
+ public ExtendedHandler( ProtocolModule a_module )
+ {
+ m_module = a_module ;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // RequestHandler Interface Method Implementations
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Gets the handler type.
+ *
+ * @return a HandlerTypeEnum constant.
+ */
+ public HandlerTypeEnum getHandlerType()
+ {
+ return HandlerTypeEnum.SINGLEREPLY ;
+ }
+
+
+ /**
+ * Gets the request message type handled by this handler.
+ *
+ * @return a MessageTypeEnum constant associated with the request message.
+ */
+ public MessageTypeEnum getRequestType()
+ {
+ return MessageTypeEnum.EXTENDEDREQ ;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // RequestHandler Interface Method Implementations
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Gets the response message type for this SingleReplyHandler.
+ *
+ * @return the MessageTypeEnum constant associated with this handler.
+ */
+ public MessageTypeEnum getResponseType()
+ {
+ return MessageTypeEnum.ADDRESPONSE ;
+ }
+
+
+ /**
+ * Handles a request that generates a sole response by returning the
+ * response object back to the caller.
+ *
+ * @param a_request the request to handle.
+ * @return the response to the request argument.
+ * @throws ClassCastException if a_request is not a AddRequest
+ */
+ public ResultResponse handle( SingleReplyRequest a_request )
+ {
+ AddRequest l_request = ( AddRequest ) a_request ;
+ throw new NotImplementedException() ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/HandlerTypeEnum.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/HandlerTypeEnum.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,55 @@
+/*
+ * $Id: HandlerTypeEnum.java,v 1.2 2003/08/22 21:15:56 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.protocol ;
+
+
+import org.apache.avalon.framework.ValuedEnum ;
+
+
+/**
+ * Valued enumeration for the three types of handlers: NOREPLY, SINGLEREPLY,
+ * and SEARCH.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.2 $
+ */
+public class HandlerTypeEnum
+ extends ValuedEnum
+{
+ /** Value for noreply enumeration type */
+ public static final int NOREPLY_VAL = 0 ;
+ /** Value for singlereply enumeration type */
+ public static final int SINGLEREPLY_VAL = 1 ;
+ /** Value for search enumeration type */
+ public static final int SEARCH_VAL = 2 ;
+
+ /** Enum for noreply type */
+ public static final HandlerTypeEnum NOREPLY =
+ new HandlerTypeEnum("NOREPLY", NOREPLY_VAL) ;
+ /** Enum for singlereply type */
+ public static final HandlerTypeEnum SINGLEREPLY =
+ new HandlerTypeEnum("SINGLEREPLY", SINGLEREPLY_VAL) ;
+ /** Enum for search type */
+ public static final HandlerTypeEnum SEARCH =
+ new HandlerTypeEnum("SEARCH", SEARCH_VAL) ;
+
+
+ /**
+ * Enables creation of constants in this class only.
+ *
+ * @param a_name the name of the enum
+ * @param a_value the value of the enum
+ */
+ private HandlerTypeEnum( String a_name, int a_value )
+ {
+ super( a_name, a_value ) ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/ModifyDNRequestProcessor.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/ModifyDNRequestProcessor.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,258 @@
+/*
+ * $Id: ModifyDNRequestProcessor.java,v 1.10 2003/08/22 21:15:56 akarasulu Exp $
+ * $Prologue$
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.protocol ;
+
+
+import javax.naming.Name ;
+
+import org.apache.avalon.framework.ExceptionUtil ;
+import org.apache.avalon.framework.service.ServiceManager ;
+import org.apache.avalon.framework.service.ServiceException ;
+
+import org.apache.eve.client.ClientKey ;
+import org.apache.eve.backend.LdapEntry ;
+import org.apache.eve.backend.UnifiedBackend ;
+import org.apache.eve.event.protocol.EventManager;
+import org.apache.eve.event.protocol.ModifyDnEvent;
+
+
+/**
+ * Processes an LDAP request to modify an entry's DN either changing its name or
+ * relocation the DIT branch at an entry under a new parent entry. The protocol
+ * in <a href="http://www.faqs.org/rfcs/rfc2251.html">RFC 2251<a> defines the
+ * request processed by the RequestProcessor.
+ * <pre>
+ * The Modify DN Operation allows a client to change the leftmost (least
+ * significant) component of the name of an entry in the directory, or
+ * to move a subtree of entries to a new location in the directory. The
+ * Modify DN Request is defined as follows:
+ *
+ * ModifyDNRequest ::= [APPLICATION 12] SEQUENCE {
+ * entry LDAPDN,
+ * newrdn RelativeLDAPDN,
+ * deleteoldrdn BOOLEAN,
+ * newSuperior [0] LDAPDN OPTIONAL }
+ *
+ * </pre>
+ */
+public class ModifyDNRequestProcessor
+// extends BaseRequestProcessor
+{
+ /** Response type of this request processor class *
+ public static final int RES_TYPE = LDAPMessageChoice.MODDNRESPONSE_CID ;
+
+
+ private EventManager m_eventManager = null ;
+ private LDAPMessage m_response = null ;
+ private UnifiedBackend m_nexus = null ;
+
+
+ /**
+ * Creates and initializes the request processor.
+ *
+ public ModifyDNRequestProcessor(ClientKey a_client, LDAPMessage a_request)
+ {
+ super(a_client, a_request, RES_TYPE) ;
+ }
+
+
+ /**
+ * Processes the LDAP ModifyDN request. The parameters of the request are
+ * transduced into arguments fed into the move or modifyRdn methods of the
+ * Backend nexus. Below you'll find a description of the parameters
+ * packaged in the ModifyRdn PDU:<br>
+ * <pre>
+ * Parameters of the Modify DN Request are:
+ *
+ * - entry: the Distinguished Name of the entry to be changed. This
+ * entry may or may not have subordinate entries.
+ *
+ * - newrdn: the RDN that will form the leftmost component of the new
+ * name of the entry.
+ *
+ * - deleteoldrdn: a boolean parameter that controls whether the old RDN
+ * attribute values are to be retained as attributes of the entry, or
+ * deleted from the entry.
+ *
+ * - newSuperior: if present, this is the Distinguished Name of the entry
+ * which becomes the immediate superior of the existing entry.
+ * </pre>
+ *
+ * @return the response message envelope formulated according to the
+ * results of the ModifyDN request.
+ *
+ public LDAPMessage process()
+ {
+ try
+ {
+ ModifyDnEvent l_event = null ;
+ String l_supDnStr = getSuperiorEntryDN() ;
+ Name l_dn = m_nexus.getNormalizedName( getEntryDN() ) ;
+ Name l_rdn = m_nexus.getNormalizedName( getNewRdn() ) ;
+ Name l_superior = m_nexus.getNormalizedName( l_supDnStr ) ;
+ LdapEntry l_entry = m_nexus.read( l_dn ) ;
+
+ if ( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug( "ModifyDNRequestProcessor: delete oldrdn = "
+ + deleteOldRdn() ) ;
+ getLogger().debug( "ModifyDNRequestProcessor: dn = "
+ + l_dn ) ;
+ getLogger().debug( "ModifyDNRequestProcessor: rdn = "
+ + l_rdn ) ;
+ getLogger().debug( "ModifyDNRequestProcessor: superior = "
+ + l_superior ) ;
+ }
+
+
+ if ( l_rdn.size() > 1 )
+ {
+ setResponse( LDAPResultEnum.INVALIDDNSYNTAX, null,
+ "ModifyDn: Expecting either a null RDN or one of length 1 "
+ + "but got RDN of length " + l_rdn.size() + " for '"
+ + l_rdn + "'" ) ;
+ }
+
+
+ /*
+ * If the superior Dn String argument in the PDU is null then we
+ * have a simple rdn name change as opposed to a move operation
+ *
+ if ( l_supDnStr == null)
+ {
+ m_nexus.modifyRdn( l_entry, l_rdn, deleteOldRdn() ) ;
+ }
+ else if ( l_rdn.size() == 0 )
+ {
+ LdapEntry l_parent = m_nexus.read( l_superior ) ;
+ m_nexus.move( l_parent, l_entry ) ;
+ }
+ else
+ {
+ LdapEntry l_parent = m_nexus.read( l_superior ) ;
+ m_nexus.move( l_parent, l_entry, l_rdn, deleteOldRdn() ) ;
+ }
+
+ setResponse( LDAPResultEnum.SUCCESS, getEntryDNBytes(),
+ "DN Modifications Successfully Completed!" ) ;
+
+ }
+ catch ( Throwable t )
+ {
+ if( getLogger().isDebugEnabled() )
+ {
+ setResponse( LDAPResultEnum.OPERATIONSERROR, null, t ) ;
+ }
+ else
+ {
+ setResponse( LDAPResultEnum.OPERATIONSERROR, null,
+ t.getMessage() ) ;
+ }
+ }
+
+ return m_response ;
+ }
+
+
+ public boolean deleteOldRdn()
+ {
+ return m_request.protocolOp.modDNRequest.deleteoldrdn ;
+ }
+
+
+ public String getSuperiorEntryDN()
+ {
+ if(m_request.protocolOp.modDNRequest.newSuperior != null) {
+ return new String(m_request.protocolOp.modDNRequest.newSuperior) ;
+ } else {
+ return null ;
+ }
+ }
+
+
+ public String getNewRdn()
+ {
+ if(m_request.protocolOp.modDNRequest.newrdn != null) {
+ return new String(m_request.protocolOp.modDNRequest.newrdn) ;
+ } else {
+ return null ;
+ }
+ }
+
+
+ public String getEntryDN()
+ {
+ return new String(m_request.protocolOp.modDNRequest.entry) ;
+ }
+
+
+ public byte [] getEntryDNBytes()
+ {
+ return m_request.protocolOp.modDNRequest.entry ;
+ }
+
+
+ public void setResponse(int a_resultType, byte [] a_dn,
+ Throwable a_throwable)
+ {
+ setResponse(a_resultType, a_dn,
+ ExceptionUtil.printStackTrace(a_throwable)) ;
+ }
+
+
+ public void setResponse(int a_resultType, byte [] a_dn, String an_errMsg)
+ {
+ m_response.protocolOp.modDNResponse.resultCode.value = a_resultType ;
+
+ if(an_errMsg != null) {
+ m_response.protocolOp.modDNResponse.errorMessage =
+ an_errMsg.getBytes() ;
+ } else {
+ m_response.protocolOp.modDNResponse.errorMessage =
+ "".getBytes() ;
+ }
+
+ if(a_dn == null) {
+ m_response.protocolOp.modDNResponse.matchedDN = "".getBytes() ;
+ } else {
+ m_response.protocolOp.modDNResponse.matchedDN = a_dn ;
+ }
+ }
+
+
+ ////////////////////////
+ // Life-Cycle Methods //
+ ////////////////////////
+
+
+ public void initialize()
+ throws Exception
+ {
+ m_response = new LDAPMessage() ;
+ m_response.messageID = m_request.messageID ;
+ LDAPMessageChoice l_protocolOp = new LDAPMessageChoice() ;
+ l_protocolOp.choiceId = this.m_responseChoiceId ;
+ ModifyDNResponse l_modDNResponse = new ModifyDNResponse() ;
+ LDAPResultEnum l_resultCode = new LDAPResultEnum() ;
+ l_modDNResponse.resultCode = l_resultCode ;
+ l_protocolOp.modDNResponse = l_modDNResponse ;
+ m_response.protocolOp = l_protocolOp ;
+ }
+
+
+ public void service(ServiceManager a_manager)
+ throws ServiceException
+ {
+ m_nexus = (UnifiedBackend) a_manager.lookup(UnifiedBackend.ROLE) ;
+ m_eventManager = (EventManager) a_manager.lookup(EventManager.ROLE) ;
+ }
+ */
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/ModifyDnHandler.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/ModifyDnHandler.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,106 @@
+/*
+ * $Id: ModifyDnHandler.java,v 1.2 2003/08/22 21:15:56 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.protocol ;
+
+
+import org.apache.ldap.common.message.ResultResponse ;
+import org.apache.ldap.common.message.MessageTypeEnum ;
+import org.apache.ldap.common.NotImplementedException ;
+import org.apache.ldap.common.message.ModifyDnRequest ;
+import org.apache.ldap.common.message.SingleReplyRequest ;
+
+
+/**
+ * ModifyDnRequest handler for ModifyDn protocol requests.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.2 $
+ */
+public class ModifyDnHandler
+ implements SingleReplyHandler
+{
+ /** The protocol module this request handler is part of */
+ private final ProtocolModule m_module ;
+
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Creates a ModifyDnRequest protocol data unit handler.
+ *
+ * @param a_module the module this handler is associated with.
+ */
+ public ModifyDnHandler( ProtocolModule a_module )
+ {
+ m_module = a_module ;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // RequestHandler Interface Method Implementations
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Gets the handler type.
+ *
+ * @return a HandlerTypeEnum constant.
+ */
+ public HandlerTypeEnum getHandlerType()
+ {
+ return HandlerTypeEnum.SINGLEREPLY ;
+ }
+
+
+ /**
+ * Gets the request message type handled by this handler.
+ *
+ * @return a MessageTypeEnum constant associated with the request message.
+ */
+ public MessageTypeEnum getRequestType()
+ {
+ return MessageTypeEnum.MODDNREQUEST ;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // RequestHandler Interface Method Implementations
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Gets the response message type for this SingleReplyHandler.
+ *
+ * @return the MessageTypeEnum constant associated with this handler.
+ */
+ public MessageTypeEnum getResponseType()
+ {
+ return MessageTypeEnum.MODDNRESPONSE ;
+ }
+
+
+ /**
+ * Handles a request that generates a sole response by returning the
+ * response object back to the caller.
+ *
+ * @param a_request the request to handle.
+ * @return the response to the request argument.
+ * @throws ClassCastException if a_request is not a ModifyRequest
+ */
+ public ResultResponse handle( SingleReplyRequest a_request )
+ {
+ ModifyDnRequest l_request = ( ModifyDnRequest ) a_request ;
+ throw new NotImplementedException() ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/ModifyHandler.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/ModifyHandler.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,173 @@
+/*
+ * $Id: ModifyHandler.java,v 1.2 2003/08/22 21:15:56 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.protocol ;
+
+
+import org.apache.ldap.common.message.ModifyRequest ;
+import org.apache.ldap.common.message.ResultResponse ;
+import org.apache.ldap.common.message.MessageTypeEnum ;
+import org.apache.ldap.common.message.SingleReplyRequest ;
+import javax.naming.Name;
+import org.apache.eve.backend.UnifiedBackend;
+import org.apache.ldap.common.message.ModifyResponseImpl;
+import org.apache.ldap.common.message.ModifyResponse;
+import java.util.Iterator;
+import javax.naming.directory.ModificationItem;
+import org.apache.eve.backend.LdapEntry;
+import org.apache.ldap.common.message.ResultCodeEnum;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.Attribute;
+
+
+/**
+ * ModifyRequest handler for modify protocol requests.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.2 $
+ */
+public class ModifyHandler
+ implements SingleReplyHandler
+{
+ /** The protocol module this request handler is part of */
+ private final ProtocolModule m_module ;
+
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Creates a ModifyRequest protocol data unit handler.
+ *
+ * @param a_module the module this handler is associated with.
+ */
+ public ModifyHandler( ProtocolModule a_module )
+ {
+ m_module = a_module ;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // RequestHandler Interface Method Implementations
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Gets the handler type.
+ *
+ * @return a HandlerTypeEnum constant.
+ */
+ public HandlerTypeEnum getHandlerType()
+ {
+ return HandlerTypeEnum.SINGLEREPLY ;
+ }
+
+
+ /**
+ * Gets the request message type handled by this handler.
+ *
+ * @return a MessageTypeEnum constant associated with the request message.
+ */
+ public MessageTypeEnum getRequestType()
+ {
+ return MessageTypeEnum.MODIFYREQUEST ;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // RequestHandler Interface Method Implementations
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Gets the response message type for this SingleReplyHandler.
+ *
+ * @return the MessageTypeEnum constant associated with this handler.
+ */
+ public MessageTypeEnum getResponseType()
+ {
+ return MessageTypeEnum.MODIFYRESPONSE ;
+ }
+
+
+ /**
+ * Handles a request that generates a sole response by returning the
+ * response object back to the caller.
+ *
+ * @param a_request the request to handle.
+ * @return the response to the request argument.
+ * @throws ClassCastException if a_request is not a ModifyRequest
+ */
+ public ResultResponse handle( SingleReplyRequest a_request )
+ {
+ Name l_dn = null ;
+ LdapEntry l_entry ;
+ UnifiedBackend l_nexus = m_module.getNexus() ;
+ ModifyRequest l_request = ( ModifyRequest ) a_request ;
+ ModifyResponse l_response =
+ new ModifyResponseImpl( a_request.getMessageId() ) ;
+
+ try
+ {
+ l_dn = m_module.getName( l_request.getName() ) ;
+
+ if( ! l_nexus.hasEntry( l_dn ) )
+ {
+ m_module.setResult( l_response, ResultCodeEnum.NOSUCHOBJECT,
+ l_dn, "Entry does not exist - modification not possible" ) ;
+ return l_response ;
+ }
+
+ l_entry = l_nexus.read( l_dn ) ;
+
+ Iterator l_list = l_request.getModificationItems().iterator() ;
+ while( l_list.hasNext() )
+ {
+ ModificationItem l_item = ( ModificationItem ) l_list.next() ;
+ Attribute l_attr = l_item.getAttribute() ;
+
+ switch( l_item.getModificationOp() )
+ {
+ case( DirContext.ADD_ATTRIBUTE ):
+ for( int ii = 0; ii > l_attr.size(); ii++ )
+ {
+ l_entry.addValue( l_attr.getID(), l_attr.get( ii ) ) ;
+ }
+ break ;
+ case( DirContext.REMOVE_ATTRIBUTE ):
+ for( int ii = 0; ii > l_attr.size(); ii++ )
+ {
+ l_entry.removeValue( l_attr.getID(),
+ l_attr.get( ii ) ) ;
+ }
+ break ;
+ case( DirContext.REPLACE_ATTRIBUTE ):
+ l_entry.removeValues( l_attr.getID() ) ;
+ for( int ii = 0; ii < l_attr.size(); ii++ )
+ {
+ l_entry.addValue( l_attr.getID(), l_attr.get( ii ) ) ;
+ }
+ break ;
+ }
+ }
+
+ l_nexus.update( l_entry ) ;
+ m_module.setResult( l_response, l_dn ) ;
+ }
+ catch( Throwable t )
+ {
+ m_module.setResult( l_response, l_dn, t ) ;
+ }
+
+ return l_response ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/NoReplyHandler.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/NoReplyHandler.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,33 @@
+/*
+ * $Id: NoReplyHandler.java,v 1.2 2003/08/22 21:15:56 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.protocol ;
+
+
+import org.apache.ldap.common.message.Request ;
+
+
+/**
+ * Represents handlers that do not return a response to the sender.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.2 $
+ */
+public interface NoReplyHandler
+ extends RequestHandler
+{
+ /**
+ * Handles requests that do not reply to the requesting client with a
+ * response.
+ *
+ * @param a_request the request without a response.
+ */
+ void handle( Request a_request ) ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/ProtocolEngine.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/ProtocolEngine.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,36 @@
+/*
+ * $Id: ProtocolEngine.java,v 1.5 2003/08/22 21:15:56 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.protocol ;
+
+
+import org.apache.eve.event.RequestListener ;
+import org.apache.eve.client.ClientManagerSlave ;
+
+
+/**
+ * Service interface for an LDAP protocol engine.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.5 $
+ */
+public interface ProtocolEngine
+ extends RequestListener, ClientManagerSlave
+{
+ /** The fully qualified name of this service interface */
+ String ROLE = ProtocolEngine.class.getName() ;
+
+ /**
+ * Gets the highest LDAP protocol version supported by an implementation.
+ *
+ * @return the highest supported protocol version.
+ */
+ int getProtocolVersion() ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/ProtocolException.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/ProtocolException.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,38 @@
+/*
+ * $Id: ProtocolException.java,v 1.3 2003/03/13 18:27:54 akarasulu Exp $
+ * $Prologue$
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.protocol ;
+
+
+import org.apache.avalon.framework.CascadingRuntimeException ;
+
+
+/** This exception is thrown when protocol errors occurred */
+public class ProtocolException extends CascadingRuntimeException
+{
+ /**
+ * Constructs an Exception with a detailed message.
+ * @param Message The message associated with the exception.
+ */
+ public ProtocolException(String message, Throwable t)
+ {
+ super(message, t) ;
+ }
+
+
+ /**
+ * Constructs an Exception with a detailed message.
+ * @param Message The message associated with the exception.
+ */
+ public ProtocolException(String message)
+ {
+ super(message, null) ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/ProtocolModule.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/ProtocolModule.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,786 @@
+/*
+ * $Id: ProtocolModule.java,v 1.11 2003/08/22 21:15:56 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.protocol ;
+
+
+import java.util.Map ;
+import java.util.HashMap ;
+import java.util.EventObject ;
+
+import javax.naming.Name ;
+import javax.naming.NamingException ;
+
+import org.apache.avalon.framework.logger.Logger ;
+import org.apache.avalon.framework.ExceptionUtil ;
+import org.apache.avalon.framework.service.ServiceManager ;
+import org.apache.avalon.framework.service.ServiceException ;
+import org.apache.avalon.framework.configuration.Configuration ;
+import org.apache.avalon.framework.configuration.ConfigurationException ;
+
+import org.apache.ldap.common.name.LdapName ;
+import org.apache.ldap.common.message.Request ;
+import org.apache.ldap.common.message.LdapResult ;
+import org.apache.ldap.common.message.SearchRequest ;
+import org.apache.ldap.common.message.ResultResponse ;
+import org.apache.ldap.common.message.LdapResultImpl ;
+import org.apache.ldap.common.message.ResultCodeEnum ;
+import org.apache.ldap.common.message.AddResponseImpl ;
+import org.apache.ldap.common.message.BindResponseImpl ;
+import org.apache.ldap.common.message.MessageTypeEnum ;
+import org.apache.ldap.common.message.ModifyResponseImpl ;
+import org.apache.ldap.common.message.SingleReplyRequest ;
+import org.apache.ldap.common.message.DeleteResponseImpl ;
+import org.apache.ldap.common.message.CompareResponseImpl ;
+import org.apache.ldap.common.message.ExtendedResponseImpl ;
+import org.apache.ldap.common.message.ModifyDnResponseImpl ;
+
+import org.apache.eve.encoder.Encoder ;
+import org.apache.eve.client.ClientKey ;
+import org.apache.eve.seda.AbstractStage ;
+import org.apache.eve.event.RequestEvent ;
+import org.apache.eve.event.ResponseEvent ;
+import org.apache.eve.client.ClientManager ;
+import org.apache.eve.output.OutputManager ;
+import org.apache.eve.backend.UnifiedBackend ;
+import org.apache.eve.event.AbstractEventHandler ;
+import org.apache.eve.event.protocol.EventManager ;
+import org.apache.eve.protocol.extended.PayloadHandler ;
+import org.apache.eve.security.auth.AuthenticationManager ;
+
+import javax.naming.ldap.LdapContext ;
+import java.util.Hashtable ;
+import javax.naming.Context ;
+import javax.naming.InitialContext ;
+
+
+/**
+ * Protocol engine stage: the request processing stage of the pipeline.
+ *
+ * @phoenix:block
+ * @phoenix:service name="org.apache.eve.protocol.ProtocolEngine"
+ * @phoenix:mx-topic name="ProtocolModule"
+ */
+public class ProtocolModule
+ extends AbstractStage
+ implements ProtocolEngine
+{
+ /** The version support by this ProtocolEngine */
+ public static final int PROTOCOL_VERSION = 3 ;
+ /** Extended request handler configuration tag name */
+ public static final String HANDLER_TAG = "handler" ;
+ /** Extended request handler configuration 'oid' attribute name */
+ public static final String OID_ATTR = "oid" ;
+ /** Extended request handler configuration handler 'class' attribute name */
+ public static final String CLASS_ATTR = "class" ;
+
+ /** Lookup Table of MessageTypeEnums to the Request's respective handler */
+ private Map m_handlers = new HashMap( 10 ) ;
+ /** Map of extended request OIDs to the respective request handlers */
+ private Map m_extendedHandlers = new HashMap() ;
+
+
+ // ------------------------------------------------------------------------
+ // Blocks the ProtocolModule depends on
+ // ------------------------------------------------------------------------
+
+ /** Reference to the event manager to dispatch protocol events */
+ private EventManager m_eventManager = null ;
+ /** Reference to the client manager to manage client sessions */
+ private ClientManager m_clientManager = null ;
+ /** Reference to the nexus which several request handlers depend on */
+ private UnifiedBackend m_nexus = null ;
+ /** Reference to the authentication manager for bind operations */
+ private AuthenticationManager m_authManager = null ;
+ /** Reference to the encoder to hande off response events to */
+ private Encoder m_encoder = null ;
+ /** Reference to the output manager synchronously search responses */
+ private OutputManager m_outputManager = null ;
+
+ // ------------------------------------------------------------------------
+ // Explicit Default Constructor
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Instantiates this module and creates the stage event handler so it can
+ * be log enabled in the first lifecycle method.
+ *
+ * @todo look into the correct way to enable logging in these handlers while
+ * making their instantiation reside within the initialize life-cycle
+ * method.
+ */
+ public ProtocolModule()
+ {
+ m_handler = new RequestEventHandler() ;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // RequestListener Interface Method Implementations
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Recieves a SEDA RequstEvent by simply enqueing it onto the stage queue.
+ *
+ * @param a_event the enqueued RequestEvent
+ */
+ public void requestReceived( RequestEvent a_event )
+ {
+ enqueue(a_event) ;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // ProtocolEngine Interface Method Implementations
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Gets the protocol version of this ProtocolEngine implementation.
+ *
+ * @return 2 if the protocol implementation is LDAPv2, otherwise 3
+ * @phoenix:mx-attribute
+ * @phoenix:mx-description the LDAP protocol version of this module.
+ * @phoenix:mx-isWriteable no
+ */
+ public int getProtocolVersion()
+ {
+ return PROTOCOL_VERSION ;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // ClientManagerSlave Interface Method Implementation
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Registers the client manager this module is to use.
+ *
+ * @param a_manager the ClientManager this module is to become the slave of.
+ */
+ public void registerClientManager(ClientManager a_manager)
+ {
+ m_clientManager = a_manager ;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // Module Interface Method Implementations.
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Gets the service interface name of this module.
+ *
+ * @return the role of this module's implemented service.
+ * @phoenix:mx-attribute
+ * @phoenix:mx-description Returns the service role name.
+ * @phoenix:mx-isWriteable no
+ */
+ public String getImplementationRole()
+ {
+ return ROLE ;
+ }
+
+
+ /**
+ * Gets the name of the implementation. For example the name of the
+ * Berkeley DB Backend module is "Berkeley DB Backend".
+ *
+ * @return String representing the module implementation type name.
+ * @phoenix:mx-attribute
+ * @phoenix:mx-description Returns the implementation name.
+ * @phoenix:mx-isWriteable no
+ */
+ public String getImplementationName()
+ {
+ return "LDAP V3 Protocol Module" ;
+ }
+
+
+ /**
+ * Gets the name of the implementation class. For example the name of the
+ * Berkeley DB Backend implementation class is <code>
+ * "ldapdd.backend.berkeley.BackendBDb" </code>.
+ *
+ * @return String representing the module implementation's class name.
+ * @phoenix:mx-attribute
+ * @phoenix:mx-description Returns the implementation class name.
+ * @phoenix:mx-isWriteable no
+ */
+ public String getImplementationClassName()
+ {
+ return this.getClass().getName() ;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // Avalon Life-Cycle Interface Method Implementations
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Enables logging for this module first through super method call then
+ * log enables this stage's event handler.
+ *
+ * @param a_logger the logger used to log enable this stage.
+ */
+ public void enableLogging( Logger a_logger )
+ {
+ super.enableLogging( a_logger ) ;
+ m_handler.enableLogging( a_logger ) ;
+ Utils.enableLogging( a_logger ) ;
+ }
+
+
+ /**
+ * Need lot of services to get the job done.
+ *
+ * @phoenix:dependency name="org.apache.eve.event.protocol.EventManager"
+ * @phoenix:dependency name="org.apache.eve.backend.UnifiedBackend"
+ * @phoenix:dependency name="org.apache.eve.security.auth.AuthenticationManager"
+ * @phoenix:dependency name="org.apache.eve.output.OutputManager"
+ * @phoenix:dependency name="org.apache.eve.encoder.Encoder"
+ * @phoenix:dependency name="org.apache.avalon.cornerstone.services.threads.ThreadManager"
+ */
+ public void service( ServiceManager a_manager )
+ throws ServiceException
+ {
+ super.service( a_manager ) ;
+ m_nexus = ( UnifiedBackend ) a_manager.lookup( UnifiedBackend.ROLE ) ;
+ m_authManager = ( AuthenticationManager )
+ a_manager.lookup( AuthenticationManager.ROLE ) ;
+ m_encoder = ( Encoder ) a_manager.lookup( Encoder.ROLE ) ;
+ m_outputManager = ( OutputManager )
+ a_manager.lookup( OutputManager.ROLE ) ;
+ m_eventManager = ( EventManager )
+ a_manager.lookup( EventManager.ROLE ) ;
+ }
+
+
+ /**
+ * Configures the module by loading extended request processor information.
+ *
+ * @param a_config the module's configuration read from config.xml
+ */
+ public void configure( Configuration a_config )
+ throws ConfigurationException
+ {
+ super.configure( a_config ) ;
+
+ PayloadHandler l_handler = null ;
+ Configuration [] l_handlers = a_config.getChildren( HANDLER_TAG ) ;
+ for( int ii = 0 ; ii < l_handlers.length ; ii++ )
+ {
+ String l_oid = l_handlers[ii].getAttribute( OID_ATTR, null ) ;
+ String l_clazz = l_handlers[ii].getAttribute( CLASS_ATTR, null ) ;
+
+ if( null == l_oid )
+ {
+ throw new ConfigurationException(
+ "Handler must have an 'oid' attribute" ) ;
+ }
+
+ if( null == l_clazz )
+ {
+ throw new ConfigurationException(
+ "Handler must have a 'class' attribute" ) ;
+ }
+
+ try
+ {
+ l_handler = ( PayloadHandler )
+ Class.forName( l_clazz ).newInstance() ;
+ }
+ catch( Exception e )
+ {
+ throw new ConfigurationException(
+ "Failed to instantiate handler class " + l_clazz
+ + " for extended request OID " + l_oid ) ;
+ }
+
+ m_extendedHandlers.put( l_oid, l_handler ) ;
+ }
+ }
+
+
+ public void initialize()
+ throws Exception
+ {
+ RequestHandler l_handler = new AbandonHandler( this ) ;
+ m_handlers.put( l_handler.getRequestType(), l_handler ) ;
+
+ l_handler = new AddHandler( this ) ;
+ m_handlers.put( l_handler.getRequestType(), l_handler ) ;
+
+ l_handler = new BindHandler( this ) ;
+ m_handlers.put( l_handler.getRequestType(), l_handler ) ;
+
+ l_handler = new CompareHandler( this ) ;
+ m_handlers.put( l_handler.getRequestType(), l_handler ) ;
+
+ l_handler = new DeleteHandler( this ) ;
+ m_handlers.put( l_handler.getRequestType(), l_handler ) ;
+
+ l_handler = new ModifyHandler( this ) ;
+ m_handlers.put( l_handler.getRequestType(), l_handler ) ;
+
+ l_handler = new ExtendedHandler( this ) ;
+ m_handlers.put( l_handler.getRequestType(), l_handler ) ;
+
+ l_handler = new ModifyDnHandler( this ) ;
+ m_handlers.put( l_handler.getRequestType(), l_handler ) ;
+
+ l_handler = new SearchHandler( this ) ;
+ m_handlers.put( l_handler.getRequestType(), l_handler ) ;
+
+ l_handler = new UnbindHandler( this ) ;
+ m_handlers.put( l_handler.getRequestType(), l_handler ) ;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // Stage Event Handler Implementation.
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Stage Event Handler Implementation for RequestEvents.
+ */
+ class RequestEventHandler extends AbstractEventHandler
+ {
+ /**
+ * Event handler method for processing RequestEvents.
+ *
+ * @param a_event the RequestEvent to process.
+ */
+ public void handleEvent( EventObject a_event )
+ {
+ Request l_request = null ;
+ ClientKey l_clientKey = null ;
+
+ // Throw protocol exception if the event is not a request event.
+ if( ! ( a_event instanceof RequestEvent ) )
+ {
+ throw new ProtocolException(
+ "Unrecognized event: " + a_event ) ;
+ }
+
+ // Extract the ClientKey and Request parameters from the event
+ l_request = ( ( RequestEvent ) a_event ).getRequest() ;
+ l_clientKey = ( ClientKey )
+ ( ( RequestEvent ) a_event ).getSource() ;
+ m_clientManager.threadAssociate( l_clientKey ) ;
+ m_clientManager.threadAssociate( l_clientKey ) ;
+
+ // Get the handler if we have one defined.
+ RequestHandler l_handler = ( RequestHandler )
+ m_handlers.get( l_request.getType() ) ;
+ if( l_handler == null )
+ {
+ throw new ProtocolException( "Unknown request message type: "
+ + l_request.getType() ) ;
+ }
+
+ // Based on the handler type start request handling.
+ switch( l_handler.getHandlerType().getValue() )
+ {
+ case( HandlerTypeEnum.NOREPLY_VAL ):
+ NoReplyHandler l_noreply = ( NoReplyHandler ) l_handler ;
+ l_noreply.handle( l_request ) ;
+ break ;
+ case( HandlerTypeEnum.SINGLEREPLY_VAL ):
+ SingleReplyHandler l_single = ( SingleReplyHandler ) l_handler ;
+ doSingleReply( l_single, ( SingleReplyRequest ) l_request ) ;
+ break ;
+ case( HandlerTypeEnum.SEARCH_VAL ):
+ SearchHandler l_search = ( SearchHandler ) l_handler ;
+ l_search.handle( ( SearchRequest ) l_request ) ;
+ break ;
+ default:
+ throw new ProtocolException( "Unrecognized handler type: "
+ + l_handler.getRequestType() ) ;
+ }
+
+ m_clientManager.threadDisassociate() ;
+ }
+ }
+
+
+ private void doSingleReply( SingleReplyHandler a_handler,
+ SingleReplyRequest a_request )
+ {
+ int l_id = a_request.getMessageId() ;
+ LdapResult l_result = null ;
+ ResultResponse l_response = null ;
+
+ try
+ {
+ l_response = a_handler.handle( a_request ) ;
+ }
+
+ // If the individual handlers do not do a global catch and report this
+ // will sheild the server from complete failure on a request reporting
+ // at a minimum the stack trace that cause the request to fail.
+ catch( Throwable t )
+ {
+ switch( a_request.getResponseType().getValue() )
+ {
+ case( MessageTypeEnum.ADDRESPONSE_VAL ):
+ l_response = new AddResponseImpl( l_id ) ;
+ break ;
+ case( MessageTypeEnum.BINDRESPONSE_VAL ):
+ l_response = new BindResponseImpl( l_id ) ;
+ break ;
+ case( MessageTypeEnum.COMPARERESPONSE_VAL ):
+ l_response = new CompareResponseImpl( l_id ) ;
+ break ;
+ case( MessageTypeEnum.DELRESPONSE_VAL ):
+ l_response = new DeleteResponseImpl( l_id ) ;
+ break ;
+ case( MessageTypeEnum.EXTENDEDRESP_VAL ):
+ l_response = new ExtendedResponseImpl( l_id ) ;
+ break ;
+ case( MessageTypeEnum.MODDNRESPONSE_VAL ):
+ l_response = new ModifyDnResponseImpl( l_id ) ;
+ break ;
+ case( MessageTypeEnum.MODIFYRESPONSE_VAL ):
+ l_response = new ModifyResponseImpl( l_id ) ;
+ break ;
+ }
+
+ // @todo We should be able to email this to LDAPd auto-bug list.
+ // if some of error reporting configuration parameters are set. Or
+ // perhaps this is something best left to a logger customization.
+ String l_msg = "Encountered an operational error while processing "
+ + a_request.getType() + " request. Please report the"
+ + " the following server stack trace to the LDAPd Group:\n"
+ + ExceptionUtil.printStackTrace( t ) ;
+ getLogger().error( l_msg ) ;
+ l_result = new LdapResultImpl( l_response ) ;
+ l_result.setMatchedDn( "" ) ;
+ l_result.setErrorMessage( l_msg ) ;
+ l_result.setResultCode( ResultCodeEnum.OPERATIONSERROR ) ;
+ l_response.setLdapResult( l_result ) ;
+ }
+
+ ClientKey l_clientKey = m_clientManager.getClientKey() ;
+ ResponseEvent l_event = new ResponseEvent( l_clientKey, l_response ) ;
+ m_encoder.responseComposed( l_event ) ;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // Package Friendly Accessors For Blocks the RequestHandlers depends on
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Package friendly accessor to the EventManager for access by
+ * RequestHandlers within this package.
+ *
+ * @return the ClientManager this module depends on
+ */
+ EventManager getEventManager()
+ {
+ return m_eventManager ;
+ }
+
+
+ /**
+ * Package friendly accessor to the ClientManager for access by
+ * RequestHandlers within this package.
+ *
+ * @return the ClientManager this module depends on
+ */
+ ClientManager getClientManager()
+ {
+ return m_clientManager ;
+ }
+
+
+ /**
+ * Package friendly accessor to the UnifiedBackend for access by
+ * RequestHandlers within this package.
+ *
+ * @return the UnifiedBackend this module depends on
+ */
+ UnifiedBackend getNexus()
+ {
+ return m_nexus ;
+ }
+
+
+ /**
+ * Package friendly accessor to the AuthenticationManager for access by
+ * RequestHandlers within this package.
+ *
+ * @return the AuthenticationManager this module depends on
+ */
+ AuthenticationManager getAuthenticationManager()
+ {
+ return m_authManager ;
+ }
+
+
+ /**
+ * Package friendly accessor to the Encoder for access by
+ * RequestHandlers within this package.
+ *
+ * @return the Encoder this module depends on
+ */
+ Encoder getEncoder()
+ {
+ return m_encoder ;
+ }
+
+
+ /**
+ * Package friendly accessor to the OutputManager for access by
+ * RequestHandlers within this package.
+ *
+ * @return the OutputManager this module depends on
+ */
+ OutputManager getOutputManager()
+ {
+ return m_outputManager ;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // Package Friendly Utility Methods Used By RequestHandlers
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Gets the javax.naming.Name respresent a distinguished name provided as
+ * a String.
+ *
+ * @param a_dn the distinguished name String.
+ * @return the Name representing the String argument.
+ */
+ Name getName( String a_dn )
+ throws NamingException
+ {
+ if( a_dn == null || a_dn.trim().equals( "" ) )
+ {
+ return new LdapName() ;
+ }
+
+ return m_nexus.getName( a_dn ) ;
+ }
+
+
+ /**
+ * Specifically used for operational errors (a.k.a. unexplained exceptions).
+ *
+ * @param a_response the ResultResponse object to build the result for
+ * @param a_dn the dn associated with the request used to find the
+ * matchingDn for the response.
+ * @param t the throwable if any associated with the result.
+ */
+ void setResult( ResultResponse a_response, Name a_dn, Throwable t )
+ {
+ setResult( a_response, ResultCodeEnum.OPERATIONSERROR, a_dn,
+ "Operational error encountered please contact report trace!", t ) ;
+ }
+
+
+ /**
+ * Overload used for successful results.
+ *
+ * @param a_response the ResultResponse object to build the result for
+ * @param a_dn the dn associated with the request used to find the
+ * matchingDn for the response.
+ */
+ void setResult( ResultResponse a_response, Name a_dn )
+ {
+ setResult( a_response, ResultCodeEnum.SUCCESS, a_dn, null, null ) ;
+ }
+
+
+ /**
+ * Utility function that creates and populates an LdapResult into a
+ * ResultResponse. So many places used this same code we had to put
+ * the it into one place as a utility function.
+ *
+ * @param a_response the ResultResponse object to build the result for
+ * @param a_resultCode the returned error code.
+ * @param a_dn the dn associated with the request used to find the
+ * matchingDn for the response.
+ * @param a_msg the error message to use.
+ */
+ void setResult( ResultResponse a_response, ResultCodeEnum a_resultCode,
+ Name a_dn, String a_msg )
+ {
+ setResult( a_response, a_resultCode, a_dn, a_msg, null ) ;
+ }
+
+
+ /**
+ * Utility function that creates and populates an LdapResult into a
+ * ResultResponse when the matched Dn is unknown or irrelavent.
+ *
+ * @param a_response the ResultResponse object to build the result for
+ * @param a_resultCode the returned error code.
+ * @param a_msg the error message to use.
+ * @param t the throwable if any associated with the result.
+ */
+ void setResult( ResultResponse a_response, ResultCodeEnum a_resultCode,
+ String a_msg, Throwable t )
+ {
+ setResult( a_response, a_resultCode, null, a_msg, t ) ;
+ }
+
+
+ /**
+ * Utility function that creates and populates an LdapResult into a
+ * ResultResponse. So many places used this same code we had to put
+ * the it into one place as a utility function.
+ *
+ * @param a_response the ResultResponse object to build the result for
+ * @param a_resultCode the returned error code.
+ * @param a_dn the dn associated with the request used to find the
+ * matchingDn for the response.
+ * @param a_msg the error message to use.
+ * @param t the throwable if any associated with the result.
+ */
+ void setResult( ResultResponse a_response, ResultCodeEnum a_resultCode,
+ Name a_dn, String a_msg, Throwable t )
+ {
+ // Initialize the result object and set it in the response
+ LdapResult l_result = new LdapResultImpl( a_response ) ;
+ a_response.setLdapResult( l_result ) ;
+
+ // Log the error if this result is associated with a non null Throwable,
+ // error message and is not a part of a successful response.
+ if( t != null && a_msg != null &&
+ a_resultCode != ResultCodeEnum.SUCCESS )
+ {
+ getLogger().error( a_msg, t ) ;
+ }
+
+ // Do no error message if all is null
+ if( a_msg == null && t == null )
+ {
+ l_result.setErrorMessage( "" ) ;
+ }
+ // Use a_msg in error message if throwable is null only
+ else if( t == null && a_msg != null )
+ {
+ l_result.setErrorMessage( a_msg ) ;
+ }
+ // Use the stack trace as error message if a_msg is null and debug is on
+ else if( a_msg == null && t != null )
+ {
+ if( getLogger().isDebugEnabled() )
+ {
+ l_result.setErrorMessage( ExceptionUtil.printStackTrace( t ) ) ;
+ }
+ }
+ // When a_msg and t are not null
+ else
+ {
+ // Only append stack trace if debugging is enabled
+ if( getLogger().isDebugEnabled() )
+ {
+ l_result.setErrorMessage( a_msg
+ + ExceptionUtil.printStackTrace( t ) ) ;
+ }
+ // Do not append stack trace if debugging is off
+ else
+ {
+ l_result.setErrorMessage( a_msg ) ;
+ }
+ }
+
+
+ l_result.setResultCode( a_resultCode ) ;
+
+ if( a_dn == null )
+ {
+ a_dn = new LdapName() ;
+ }
+
+ try
+ {
+ Name l_matchedDn = m_nexus.getMatchedDn( a_dn ) ;
+ l_result.setMatchedDn( l_matchedDn.toString() ) ;
+ }
+ // Regardless of exception this is an operational error
+ catch( Exception e )
+ {
+ StringBuffer l_buf = new StringBuffer() ;
+ l_buf.append( "Could not find matching Dn for '" ) ;
+ l_buf.append( a_dn ) ;
+ l_buf.append( "' due to operational error: " ) ;
+ l_buf.append( e.getMessage() ) ;
+ String l_msg = l_buf.toString() ;
+
+ l_result.setMatchedDn( "" ) ;
+ l_result.setErrorMessage( l_msg ) ;
+ l_result.setResultCode( ResultCodeEnum.OPERATIONSERROR ) ;
+ getLogger().error( l_msg, e ) ;
+ }
+ }
+
+
+ /**
+ * Utility method to get ahold of an ldap context based on a DN.
+ *
+ * @param a_dn the distinguished name of the ldap entry to get a JNDI context to.
+ * @return the context associated with an entry specified by dn.
+ */
+ public LdapContext getContext( String a_dn )
+ throws NamingException
+ {
+ return getContext( getName( a_dn ) ) ;
+ }
+
+
+ /**
+ * Utility method to get ahold of an ldap context based on a DN.
+ *
+ * @param a_dn the distinguished name of the ldap entry to get a JNDI context to.
+ * @return the context associated with an entry specified by dn.
+ */
+ public LdapContext getContext( Name a_dn )
+ throws NamingException
+ {
+ Hashtable l_env = new Hashtable() ;
+ InitialContext l_initialContext = null ;
+
+ l_env.put( Context.INITIAL_CONTEXT_FACTORY,
+ "org.apache.eve.jndi.ServerContextFactory" ) ;
+ l_initialContext = new InitialContext( l_env ) ;
+ return ( LdapContext ) l_initialContext.lookup( a_dn ) ;
+ }
+
+
+ /**
+ * Utility method to get then initial context.
+ *
+ * @return the initial context for the directory.
+ */
+ public InitialContext getInitialContext()
+ throws NamingException
+ {
+ Hashtable l_env = new Hashtable() ;
+ l_env.put( Context.INITIAL_CONTEXT_FACTORY,
+ "org.apache.eve.jndi.ServerContextFactory" ) ;
+ return new InitialContext( l_env ) ;
+ }
+}
+
+
+
+
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/RequestHandler.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/RequestHandler.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,38 @@
+/*
+ * $Id: RequestHandler.java,v 1.2 2003/08/22 21:15:56 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.protocol ;
+
+
+import org.apache.ldap.common.message.MessageTypeEnum ;
+
+
+/**
+ * Root of all request handler types.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.2 $
+ */
+public interface RequestHandler
+{
+ /**
+ * Gets the handler type.
+ *
+ * @return a HandlerTypeEnum constant.
+ */
+ HandlerTypeEnum getHandlerType() ;
+
+ /**
+ * Gets the request message type handled by this handler.
+ *
+ * @return a MessageTypeEnum constant associated with the request message.
+ */
+ MessageTypeEnum getRequestType() ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/SearchHandler.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/SearchHandler.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,330 @@
+/*
+ * $Id: SearchHandler.java,v 1.2 2003/08/22 21:15:56 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+
+package org.apache.eve.protocol ;
+
+
+import java.util.Iterator ;
+import java.util.HashSet;
+import java.util.Collections;
+
+import java.io.IOException ;
+import java.io.ByteArrayInputStream ;
+import java.rmi.Naming;
+
+import javax.naming.Name ;
+import javax.naming.NamingException;
+
+import org.apache.ldap.common.Lockable ;
+import org.apache.ldap.common.message.Response ;
+import org.apache.ldap.common.message.SearchRequest ;
+import org.apache.ldap.common.message.ResultCodeEnum ;
+import org.apache.ldap.common.message.MessageTypeEnum ;
+import org.apache.ldap.common.message.LockableAttribute ;
+import org.apache.ldap.common.message.LockableAttributes ;
+import org.apache.ldap.common.message.SearchResponseDone ;
+import org.apache.ldap.common.message.SearchResponseEntry ;
+import org.apache.ldap.common.message.LockableAttributeImpl ;
+import org.apache.ldap.common.message.SearchResponseDoneImpl ;
+import org.apache.ldap.common.message.LockableAttributesImpl ;
+import org.apache.ldap.common.message.SearchResponseEntryImpl ;
+
+import org.apache.eve.backend.Cursor ;
+import org.apache.eve.client.ClientKey ;
+import org.apache.eve.backend.LdapEntry ;
+import org.apache.ldap.common.message.ScopeEnum ;
+import org.apache.eve.backend.UnifiedBackend ;
+import org.apache.eve.schema.Schema;
+
+
+/**
+ * SearchRequest handler.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.2 $
+ */
+public class SearchHandler
+ implements RequestHandler
+{
+ /** The protocol module this handler is used by */
+ private final ProtocolModule m_module ;
+
+
+ // ------------------------------------------------------------------------
+ // Constructor
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Creates a SearchRequest handler instance for use by a ProtocolModule.
+ *
+ * @param a_module the ProtocolModule this instance is created for.
+ */
+ public SearchHandler( ProtocolModule a_module )
+ {
+ m_module = a_module ;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // SearchHandler's Primary Handling Method
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Specifically designed handler method for processing SearchRequests
+ *
+ * @param a_request the SearchRequest to handle
+ */
+ public void handle( SearchRequest a_request )
+ {
+ Name l_base = null ;
+ UnifiedBackend l_nexus = m_module.getNexus() ;
+
+ try
+ {
+ // Get the normalized search base as a Name
+ l_base = m_module.getName( a_request.getBase() ) ;
+
+ // Return NOSUCHOBJECT done response if the search base is not there
+ if( ! l_nexus.hasEntry( l_base ) )
+ {
+ sendSearchDone(a_request, ResultCodeEnum.NOSUCHOBJECT, l_base,
+ "Search base not found.", null) ;
+ }
+
+ // Get a cursor over the search results
+ Cursor l_cursor = l_nexus.search( a_request.getFilter(), l_base,
+ a_request.getScope().getValue() ) ;
+
+ // For each LdapEntry send back a SearchResponseEntry PDU to client
+ while( l_cursor.hasMore() )
+ {
+ LdapEntry l_entry = ( LdapEntry ) l_cursor.next() ;
+
+ // Some backends make the suffix a parent/child of itself
+ // so we need to catch a return of the suffix if the base
+ // in a single scoped search.
+ if( l_entry.getNormalizedDN().equals( l_base )
+ && a_request.getScope() == ScopeEnum.SINGLELEVEL )
+ {
+ continue ;
+ }
+
+ sendEntry( a_request, l_entry ) ;
+ }
+
+ // Complete search with a successful SearchResponseDone PDU
+ sendSearchDone( a_request, l_base ) ;
+ }
+ catch( Throwable t )
+ {
+ // Sent a search response done to handle any exceptional conditions
+ // that may have been encountered during search request handling.
+ sendSearchDone( a_request, t ) ;
+ }
+ }
+
+
+ // ------------------------------------------------------------------------
+ // RequestHandler Interface Method Implementations
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Gets the handler type for this RequestHandler.
+ *
+ * @return HandlerTypeEnum.SEARCH always
+ */
+ public HandlerTypeEnum getHandlerType()
+ {
+ return HandlerTypeEnum.SEARCH ;
+ }
+
+
+ /**
+ * Gets the message type this handler is designed to respond to.
+ *
+ * @return MessageTypeEnum.SEARCHREQUEST always.
+ */
+ public MessageTypeEnum getRequestType()
+ {
+ return MessageTypeEnum.SEARCHREQUEST ;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // Utility Methods Used by Search Handler Method
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Gets the attributes view of the entry by copying LdapEntry attributes and
+ * their values into a LockableAttributes object.
+ *
+ * @param req the search request
+ * @param a_parent the Lockable parent used by the LockableAttributes
+ * @param a_entry the entry to transform into a LockableAttributes instance
+ * @return the LockableAttributes representation of the LdapEntry
+ */
+ private LockableAttributes
+ getAttributes( SearchRequest req, Lockable a_parent, LdapEntry a_entry )
+ {
+ // Create the LockableAttributes using the default implementation
+ LockableAttributes l_attributes =
+ new LockableAttributesImpl( a_parent ) ;
+ Schema schema = null ;
+
+ try
+ {
+ Name ndn = a_entry.getNormalizedDN() ;
+ schema = m_module.getNexus().getSchema(ndn) ;
+ }
+ catch( NamingException e )
+ {
+ m_module.getLogger().error("dn normalization failed", e) ;
+ }
+
+ // Iterate through the set of attributes in the entry.
+ Iterator l_list = a_entry.attributes().iterator() ;
+ while( l_list.hasNext() )
+ {
+ // Get the name/id of the attribute and create a LockableAttribute
+ // using the default implementation and add it to the attributes
+ String l_id = ( String ) l_list.next() ;
+
+ // build a hashtable of requested ids
+ HashSet requestedIds = new HashSet() ;
+ requestedIds.addAll( req.getAttributes() ) ;
+
+ LockableAttribute l_attribute = null ;
+
+ if ( requestedIds.size() == 0 && schema.isOperational(l_id) )
+ {
+ continue ;
+ }
+ else if ( requestedIds.size() != 0 && !requestedIds.contains(l_id) )
+ {
+ continue ;
+ }
+
+ l_attribute = new LockableAttributeImpl( l_attributes, l_id ) ;
+ l_attributes.put( l_attribute ) ;
+
+ // Add the values of the attribute in the entry to the Attribute
+ Iterator l_values = a_entry.getMultiValue( l_id ).iterator() ;
+ while( l_values.hasNext() )
+ {
+ l_attribute.add( l_values.next() ) ;
+ }
+ }
+
+ return l_attributes ;
+ }
+
+
+ /**
+ * Sends a SearchResponseEntry containing the attributes of an LdapEntry to
+ * the client.
+ *
+ * @param a_request the request to respond to
+ * @param a_entry the LdapEntry to send in the SearchResponseEntry PDU
+ */
+ private void sendEntry( SearchRequest a_request, LdapEntry a_entry )
+ {
+ SearchResponseEntry l_response =
+ new SearchResponseEntryImpl( a_request.getMessageId() ) ;
+ l_response.setObjectName( a_entry.getEntryDN() ) ;
+ l_response.setAttributes( getAttributes( a_request,
+ l_response, a_entry ) ) ;
+ transmit( l_response ) ;
+ }
+
+
+ /**
+ * Sends a SearchResponseDone for a specific error using its result code and
+ * error message.
+ *
+ * @param a_request the request to respond to
+ * @param a_resultCode the LdapResult result code enumeration to use
+ * @param a_dn the search base which is used to determine the matching Dn
+ * @param a_msg the custom error message to send
+ * @param a_error the error causing the negative response to the client
+ */
+ private void sendSearchDone( SearchRequest a_request,
+ ResultCodeEnum a_resultCode, Name a_dn, String a_msg,
+ Throwable a_error )
+ {
+ SearchResponseDone l_response =
+ new SearchResponseDoneImpl( a_request.getMessageId() ) ;
+ m_module.setResult( l_response, a_resultCode, a_dn, a_msg, a_error ) ;
+ transmit( l_response ) ;
+ }
+
+
+ /**
+ * Sends a SearchResponseDone for a specific error the result code and
+ * error messages may be generated from the type of error that results. In
+ * a sense this overload is the generic exception handler for this request
+ * handler.
+ *
+ * @param a_request the request to respond to
+ * @param a_error the error causing the negative response to the client
+ */
+ private void sendSearchDone( SearchRequest a_request, Throwable a_error )
+ {
+ SearchResponseDone l_response =
+ new SearchResponseDoneImpl( a_request.getMessageId() ) ;
+ m_module.setResult( l_response, null, a_error ) ;
+ transmit( l_response ) ;
+ }
+
+
+ /**
+ * Sends a successful SearchResponseDone.
+ *
+ * @param a_request the request to respond to
+ * @param a_dn the search base which is used to determine the matching Dn
+ */
+ private void sendSearchDone( SearchRequest a_request, Name a_dn )
+ {
+ SearchResponseDone l_response =
+ new SearchResponseDoneImpl( a_request.getMessageId() ) ;
+ m_module.setResult( l_response, a_dn ) ;
+ transmit( l_response ) ;
+ }
+
+
+ /**
+ * Synchronously transmits a response to the client using special
+ * synchronous interfaces on the Encoder and OutputManager.
+ *
+ * @param a_response the response to transmit to the client.
+ */
+ private void transmit( Response a_response )
+ {
+ byte l_buf[] = m_module.getEncoder().encode( a_response ) ;
+ ByteArrayInputStream l_in = new ByteArrayInputStream( l_buf ) ;
+ ClientKey l_clientKey = m_module.getClientManager().getClientKey() ;
+
+ try
+ {
+ m_module.getOutputManager().write( l_clientKey, l_in ) ;
+ }
+ catch( IOException ioe )
+ {
+ m_module.getClientManager().drop( l_clientKey ) ;
+ m_module.getLogger().error(
+ "Failed to transmit pdu to client " + l_clientKey.toString()
+ + ". Client has been dropped." ) ;
+ }
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/SearchRequestProcessor.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/SearchRequestProcessor.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,554 @@
+/*
+ * $Id: SearchRequestProcessor.java,v 1.22 2003/08/22 21:15:56 akarasulu Exp $
+ * $Prologue$
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.protocol ;
+
+
+/**
+ *
+ */
+public class SearchRequestProcessor
+// extends BaseRequestProcessor
+{
+ /** Response type of this request processor class
+ public static final int RES_TYPE = LDAPMessageChoice.SEARCHRESDONE_CID ;
+
+ private EventManager m_eventManager = null ;
+ private ExprNode m_exprNode = null ;
+ private Name m_baseDN = null ;
+ private UnifiedBackend m_nexus = null ;
+ private Encoder m_encoder = null ;
+ private OutputManager m_outputManager = null ;
+ private LDAPMessage m_response = null ;
+
+
+ /**
+ * Creates and initializes the request processor.
+ *
+ public SearchRequestProcessor(ClientKey a_client, LDAPMessage a_request)
+ {
+ super(a_client, a_request, RES_TYPE) ;
+ }
+
+
+ /**
+ * Processes the request.
+ * dummy to test protocol communication
+ * @see org.apache.eve.protocol.RequestProcessor#process()
+ *
+ public LDAPMessage process()
+ {
+ try {
+ SearchEvent l_event = null ;
+ m_baseDN = m_nexus.getNormalizedName(
+ new String( m_request.protocolOp.searchRequest.baseObject ) ) ;
+ Filter l_filter = m_request.protocolOp.searchRequest.filter ;
+ m_exprNode = ExprTreeComposer.compose( l_filter ) ;
+ SearchControls l_controls = getSearchControls() ;
+
+ if ( m_eventManager.hasListener(
+ ProtocolEvent.SEARCHREQUEST_MASK ) )
+ {
+ l_event = new SearchEvent( this, true ) ;
+ l_event.setBase( m_baseDN ) ;
+ l_event.setFilter( m_exprNode ) ;
+ l_event.setSearchControls( l_controls ) ;
+ m_eventManager.fireBefore( l_event ) ;
+ }
+ else if ( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug(
+ "No event listeners for search operations are"
+ + " enabled - SearchEvent not constucted - not fired before"
+ + " operation!" ) ;
+ }
+
+ if ( getLogger().isDebugEnabled() )
+ {
+ StringBuffer l_buf = new StringBuffer() ;
+ m_exprNode.printToBuffer( l_buf ) ;
+ getLogger().debug( "Entry DN used for search base = '"
+ + m_baseDN + "'" ) ;
+ getLogger().debug( "ASN1 Filter = " + l_filter ) ;
+ getLogger().debug( "m_exprNode = " + l_buf.toString() ) ;
+ getLogger().debug( "Search scope = " +
+ getScopeString( m_request.protocolOp.
+ searchRequest.scope.value ) ) ;
+ }
+
+ Cursor l_cursor = m_nexus.search( m_exprNode, m_baseDN,
+ l_controls.getSearchScope() ) ;
+ LdapEntry l_candidate = null ;
+
+ while ( l_cursor.hasMore() )
+ {
+ LdapEntry l_entry = ( LdapEntry ) l_cursor.next() ;
+
+ // Filters out special case where some backends return the
+ // base of a single scope search since they map themselves
+ // as their own children. According to the ldap spec we
+ // should not be returning the base on a single scope search.
+
+ if ( l_controls.getSearchScope() == Backend.SINGLE_SCOPE &&
+ l_entry.getNormalizedDN().equals( m_baseDN ) )
+ {
+ if ( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug( "Not returning base entry with dn '"
+ + l_entry.getNormalizedDN()
+ + "' in single scope search." ) ;
+ }
+
+ continue ;
+ }
+ else if ( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug( "Returning entry with dn '"
+ + l_entry.getNormalizedDN()
+ + "' in single scope search with base '"
+ + m_baseDN + "'" ) ;
+ }
+
+ if ( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug( getMessageKey()
+ + " - SearchRequestProcessor.process(): sending entry "
+ + l_entry.getEntryDN() + " to client" ) ;
+ }
+
+ //if(l_entry.isRefferal()) {
+ // sendReference(l_entry) ;
+ //} else {
+ sendEntry(l_entry) ;
+ //}
+ }
+
+ if ( l_event != null )
+ {
+ m_eventManager.fireAfter(l_event) ;
+ }
+ else if ( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug(
+ "No event listeners for search operations are"
+ + " enabled - SearchEvent not constucted - not fired after"
+ + " operation!" ) ;
+ }
+
+ return sendDone() ;
+ }
+ catch ( IllegalArgumentException e )
+ {
+ String l_errMsg = "Naming context not found!" ;
+
+ if ( getLogger().isDebugEnabled() )
+ {
+ l_errMsg += "\n" + ExceptionUtil.printStackTrace( e ) ;
+ }
+
+ return sendDone( LDAPResultEnum.NAMINGVIOLATION, l_errMsg ) ;
+ }
+ catch ( Exception e )
+ {
+ getLogger().debug( "Failed search request:\n"
+ + m_request + "\n", e ) ;
+ m_response = new LDAPMessage() ;
+ m_response.messageID = m_request.messageID ;
+ m_response.protocolOp = new LDAPMessageChoice() ;
+ m_response.protocolOp.choiceId =
+ LDAPMessageChoice.SEARCHRESDONE_CID ;
+ m_response.protocolOp.searchResDone = new SearchResultDone() ;
+ m_response.protocolOp.searchResDone.matchedDN =
+ m_request.protocolOp.searchRequest.baseObject ;
+ m_response.protocolOp.searchResDone.resultCode =
+ new LDAPResultEnum() ;
+ m_response.protocolOp.searchResDone.resultCode.value =
+ LDAPResultEnum.OPERATIONSERROR ;
+ m_response.protocolOp.searchResDone.errorMessage =
+ "failed on search request!".getBytes() ;
+ return m_response ;
+ }
+ }
+
+
+ public String [] getAttributesToReturn()
+ {
+ AttributeDescriptionList l_adl =
+ m_request.protocolOp.searchRequest.attributes ;
+ String [] l_attribsToReturn = new String [l_adl.size()] ;
+
+ for ( int ii = 0 ; ii < l_adl.size(); ii++ )
+ {
+ l_attribsToReturn[ii] =
+ new String( ( byte [] ) l_adl.elementAt( ii ) ) ;
+ }
+
+ return l_attribsToReturn ;
+ }
+
+
+ public String getScopeString( int a_scope )
+ {
+ switch ( a_scope )
+ {
+ case( SearchRequestEnum.BASEOBJECT ):
+ return "BASE" ;
+ case( SearchRequestEnum.SINGLELEVEL ):
+ return "SINGLE" ;
+ case( SearchRequestEnum.WHOLESUBTREE ):
+ return "SUBTREE" ;
+ default:
+ throw new IllegalArgumentException(
+ "The scope arg to getScopeString"
+ + " must be a SearchRequestEnum value of BASEOBJECT, SINGLELEVEL,"
+ + " or WHOLESUBTREE." ) ;
+ }
+ }
+
+
+ public SearchControls getSearchControls()
+ {
+ SearchControls l_ctls = new SearchControls() ;
+
+ if ( null != m_request.protocolOp.searchRequest.sizeLimit )
+ {
+ l_ctls.setCountLimit( m_request.protocolOp.searchRequest.
+ sizeLimit.longValue() ) ;
+ }
+
+ if ( null != m_request.protocolOp.searchRequest.derefAliases )
+ {
+ if ( m_request.protocolOp.searchRequest.derefAliases.value
+ == SearchRequestEnum1.NEVERDEREFALIASES )
+ {
+ l_ctls.setDerefLinkFlag( false ) ;
+ }
+ else
+ {
+ l_ctls.setDerefLinkFlag( true ) ;
+ }
+ }
+
+ l_ctls.setReturningAttributes( getAttributesToReturn() ) ;
+ l_ctls.setReturningObjFlag( m_request.protocolOp.searchRequest
+ .typesOnly ) ;
+
+ if ( null != m_request.protocolOp.searchRequest.timeLimit )
+ {
+ l_ctls.setTimeLimit(m_request.protocolOp.searchRequest.
+ timeLimit.intValue()) ;
+ }
+
+ if ( null != m_request.protocolOp.searchRequest.scope )
+ {
+ switch ( m_request.protocolOp.searchRequest.scope.value )
+ {
+ case( SearchRequestEnum.BASEOBJECT ):
+ l_ctls.setSearchScope( SearchControls.OBJECT_SCOPE ) ;
+ break ;
+ case( SearchRequestEnum.SINGLELEVEL ):
+ l_ctls.setSearchScope( SearchControls.ONELEVEL_SCOPE ) ;
+ break ;
+ case( SearchRequestEnum.WHOLESUBTREE ):
+ l_ctls.setSearchScope( SearchControls.SUBTREE_SCOPE ) ;
+ break ;
+ default:
+ break ;
+ }
+ }
+
+ return l_ctls ;
+ }
+
+
+ public Name getBaseDN()
+ {
+ return m_baseDN ;
+ }
+
+
+ public byte [] getBaseDNBytes()
+ {
+ return m_request.protocolOp.searchRequest.baseObject ;
+ }
+
+
+ public int getSearchScope()
+ {
+ return m_request.protocolOp.searchRequest.scope.value ;
+ }
+
+
+ public Enumeration getRequestedAttributes()
+ {
+ final AttributeDescriptionList l_adl =
+ m_request.protocolOp.searchRequest.attributes ;
+
+ if ( l_adl.size() < 0 )
+ {
+ // Returning empty enum so we don't care about converting binary
+ // bytes to a string nothing comes out of this enumeration.
+ return l_adl.elements() ;
+ }
+
+ final Enumeration l_list = l_adl.elements() ;
+ return new Enumeration()
+ {
+ public boolean hasMoreElements()
+ {
+ return l_list.hasMoreElements() ;
+ }
+
+ public Object nextElement()
+ {
+ String l_retval =
+ new String( (byte [] ) l_list.nextElement() ) ;
+
+ if ( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug( "SearchRequest Specified Attribute '"
+ + l_retval + "'" ) ;
+ }
+
+ return l_retval ;
+ }
+ } ;
+ }
+
+
+ public void sendReference( LdapEntry l_entry )
+ {
+ throw new NotImplementedException() ;
+ }
+
+
+ /**
+ * Synchronous send that does not use asynchronous event based approach.
+ *
+ public void sendEntry( LdapEntry a_entry )
+ {
+ try {
+ LDAPMessage l_pdu = new LDAPMessage() ;
+ l_pdu.messageID = m_request.messageID ;
+
+ LDAPMessageChoice l_protocolOp = new LDAPMessageChoice() ;
+ l_pdu.protocolOp = l_protocolOp ;
+ l_protocolOp.choiceId = LDAPMessageChoice.SEARCHRESENTRY_CID ;
+ SearchResultEntry l_result = new SearchResultEntry() ;
+ l_protocolOp.searchResEntry = l_result ;
+
+ l_result.attributes = new PartialAttributeList() ;
+
+ // If entry is the RootDSE then the dn could be null
+ if ( a_entry.getEntryDN() == null )
+ {
+ l_result.objectName = "".getBytes() ;
+ }
+ else
+ {
+ l_result.objectName = a_entry.getEntryDN().getBytes() ;
+ }
+
+ addTo( l_result.attributes, a_entry ) ;
+
+ byte [] l_buf = m_encoder.encode( m_client, l_pdu ) ;
+ m_outputManager.write( m_client,
+ new ByteArrayInputStream( l_buf ) ) ;
+
+ if ( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug( getMessageKey()
+ + " - SearchRequestProcessor.sendEntry(): composed "
+ + "response for entry "
+ + a_entry.getEntryDN() + ":\n" + l_pdu ) ;
+ }
+ }
+ catch( Exception e )
+ {
+ getLogger().debug( "Could not send search entry response for entry "
+ + "cadidate:\n" + a_entry, e ) ;
+ }
+ }
+
+
+ LDAPMessage sendDone()
+ {
+ LDAPMessage l_doneMsg = new LDAPMessage() ;
+
+ try {
+ getLogger().debug("search complete sending done response!") ;
+ l_doneMsg.messageID = m_request.messageID ;
+ LDAPMessageChoice l_protocolOp = new LDAPMessageChoice() ;
+ l_protocolOp.choiceId = LDAPMessageChoice.SEARCHRESDONE_CID ;
+ l_doneMsg.protocolOp = l_protocolOp ;
+
+ SearchResultDone l_result = new SearchResultDone() ;
+ l_protocolOp.searchResDone = l_result ;
+ LDAPResultEnum l_enum = new LDAPResultEnum() ;
+ l_result.resultCode = l_enum ;
+ l_enum.value = LDAPResultEnum.SUCCESS ;
+ l_result.errorMessage = "search complete!".getBytes() ;
+ l_result.matchedDN = getBaseDNBytes() ;
+ } catch(Exception e) {
+ getLogger().debug("Cant send search done response.", e) ;
+ }
+
+ return l_doneMsg ;
+ }
+
+
+ LDAPMessage sendDone(int a_resultCode, String a_message)
+ {
+ LDAPMessage l_doneMsg = new LDAPMessage() ;
+
+ try {
+ l_doneMsg.messageID = m_request.messageID ;
+ LDAPMessageChoice l_protocolOp = new LDAPMessageChoice() ;
+ l_protocolOp.choiceId = LDAPMessageChoice.SEARCHRESDONE_CID ;
+ l_doneMsg.protocolOp = l_protocolOp ;
+
+ SearchResultDone l_result = new SearchResultDone() ;
+ l_protocolOp.searchResDone = l_result ;
+ LDAPResultEnum l_enum = new LDAPResultEnum() ;
+ l_result.resultCode = l_enum ;
+ l_enum.value = a_resultCode ;
+ l_result.errorMessage = a_message.getBytes() ;
+ l_result.matchedDN = getBaseDNBytes() ;
+ } catch(Exception e) {
+ getLogger().debug("Cant send search done response.", e) ;
+ }
+
+ return l_doneMsg ;
+ }
+
+
+ /**
+ * dummy to test protocol communication
+ *
+ void addTo( PartialAttributeList a_attribs, LdapEntry a_entry )
+ throws NamingException
+ {
+ boolean l_userSpecified = false ;
+
+ // List of attributes specified for return by the user
+ Enumeration l_list = getRequestedAttributes() ;
+
+ //
+ // If the attribute description list is empty or null in the request
+ // then we need to return all non-operational attributes rather than
+ // user requested attributes which may request operational attribute
+ // values.
+ //
+
+ if( ! l_list.hasMoreElements() )
+ {
+ l_list = Collections.enumeration( a_entry.attributes() ) ;
+ l_userSpecified = false ;
+ }
+ else
+ {
+ l_userSpecified = true ;
+
+ if ( getLogger().isDebugEnabled() )
+ {
+ StringBuffer l_buf = new StringBuffer() ;
+ l_buf.append( "Looks like the user is asking for specific " ) ;
+ l_buf.append( "attributes to be returned!\nThe requested " ) ;
+ l_buf.append( "attributes are:\n" ) ;
+
+ Enumeration l_attribs = getRequestedAttributes() ;
+ while ( l_attribs.hasMoreElements() )
+ {
+ String l_attrib = ( String ) l_attribs.nextElement() ;
+ l_buf.append( "\t" ).append( l_attrib ).append( "\n" ) ;
+ }
+ getLogger().debug( l_buf.toString() ) ;
+ }
+ }
+
+
+ PartialAttributeListSeq l_seq = null ;
+ PartialAttributeListSeqSetOf l_seqSet = null ;
+
+ while ( l_list.hasMoreElements() )
+ {
+ l_seq = new PartialAttributeListSeq() ;
+ String l_name = ( String ) l_list.nextElement() ;
+
+ if ( ! a_entry.hasAttribute( l_name ) )
+ {
+ if ( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug( "Attribute '" + l_name + "' does not "
+ + "exist in entry '" + a_entry.getEntryDN() + "'\n"
+ + "values will not be returned for this requested "
+ + "attribute." ) ;
+ }
+
+ continue ;
+ }
+
+
+ if ( ! l_userSpecified &&
+ m_nexus.getSchema( m_baseDN ).isOperational( l_name ) )
+ {
+ continue ;
+ }
+
+
+ l_seq.type = l_name.getBytes() ;
+ l_seqSet = new PartialAttributeListSeqSetOf() ;
+ Iterator l_values = a_entry.getMultiValue( l_name ).iterator() ;
+ while( l_values.hasNext() )
+ {
+ Object l_value = l_values.next() ;
+ if ( l_value.getClass().isArray() )
+ {
+ l_seqSet.put( ( byte [] ) l_value, ( byte [] ) l_value ) ;
+ }
+ else
+ {
+ l_seqSet.put( ( ( String ) l_value ).getBytes(),
+ ( ( String ) l_value ).getBytes() ) ;
+ }
+ }
+
+ l_seq.vals = l_seqSet ;
+ a_attribs.add( l_seq ) ;
+ }
+ }
+
+
+ ////////////////////////
+ // Life-Cycle Methods //
+ ////////////////////////
+
+
+ public void initialize()
+ throws Exception
+ {
+ // Does nothing!
+ }
+
+
+ public void service( ServiceManager a_manager )
+ throws ServiceException
+ {
+ m_nexus = ( UnifiedBackend )
+ a_manager.lookup( UnifiedBackend.ROLE ) ;
+ m_encoder = ( Encoder )
+ a_manager.lookup( Encoder.ROLE ) ;
+ m_outputManager = ( OutputManager )
+ a_manager.lookup( OutputManager.ROLE ) ;
+ m_eventManager = ( EventManager )
+ a_manager.lookup( EventManager.ROLE ) ;
+ }
+ */
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/SingleReplyHandler.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/SingleReplyHandler.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,44 @@
+/*
+ * $Id: SingleReplyHandler.java,v 1.2 2003/08/22 21:15:56 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.protocol ;
+
+
+import org.apache.ldap.common.message.ResultResponse ;
+import org.apache.ldap.common.message.MessageTypeEnum ;
+import org.apache.ldap.common.message.SingleReplyRequest ;
+
+
+/**
+ * Request handler signature for those requests that generate a single response
+ * for a request.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.2 $
+ */
+public interface SingleReplyHandler
+ extends RequestHandler
+{
+ /**
+ * Gets the response message type for this SingleReplyHandler.
+ *
+ * @return the MessageTypeEnum constant associated with this handler.
+ */
+ MessageTypeEnum getResponseType() ;
+
+ /**
+ * Handles a request that generates a sole response by returning the
+ * response object back to the caller.
+ *
+ * @param a_request the request to handle.
+ * @return the response to the request argument.
+ */
+ ResultResponse handle( SingleReplyRequest a_request ) ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/Stats.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/Stats.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,97 @@
+/*
+ * $Id: Stats.java,v 1.2 2003/08/22 21:15:56 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.protocol ;
+
+
+import org.apache.ldap.common.message.Request ;
+import org.apache.ldap.common.message.MessageTypeEnum ;
+
+
+/**
+ * Collects statistics for protocol requests serviced by the server.
+ */
+public class Stats
+{
+ Request m_lastAbandonReq = null ;
+ Request m_lastAddReq = null ;
+ Request m_lastBindReq = null ;
+ Request m_lastCompareReq = null ;
+ Request m_lastDelReq = null ;
+ Request m_lastExtendedReq = null ;
+ Request m_lastModDNReq = null ;
+ Request m_lastModifyReq = null ;
+ Request m_lastSearchReq = null ;
+ Request m_lastUnbindReq = null ;
+ Request m_lastRequest = null ;
+
+ int m_numAbandonReq = 0 ;
+ int m_numAddReq = 0 ;
+ int m_numBindReq = 0 ;
+ int m_numCompareReq = 0 ;
+ int m_numDelReq = 0 ;
+ int m_numExtendedReq = 0 ;
+ int m_numModDNReq = 0 ;
+ int m_numModifyReq = 0 ;
+ int m_numSearchReq = 0 ;
+ int m_numUnbindReq = 0 ;
+ int m_numTotal = 0 ;
+
+
+ public void addRequest( Request a_msg )
+ {
+ m_lastRequest = a_msg ;
+ m_numTotal++ ;
+
+ switch( a_msg.getType().getValue() ) {
+ case( MessageTypeEnum.ABANDONREQUEST_VAL ):
+ m_lastAbandonReq = a_msg ;
+ m_numAbandonReq++ ;
+ break ;
+ case( MessageTypeEnum.ADDREQUEST_VAL ):
+ m_lastAddReq = a_msg ;
+ m_numAddReq++ ;
+ break ;
+ case( MessageTypeEnum.BINDREQUEST_VAL ):
+ m_lastBindReq = a_msg ;
+ m_numBindReq++ ;
+ break ;
+ case( MessageTypeEnum.COMPAREREQUEST_VAL ):
+ m_lastCompareReq = a_msg ;
+ m_numCompareReq++ ;
+ break ;
+ case( MessageTypeEnum.DELREQUEST_VAL ):
+ m_lastDelReq = a_msg ;
+ m_numDelReq++ ;
+ break ;
+ case( MessageTypeEnum.EXTENDEDREQ_VAL ):
+ m_lastExtendedReq = a_msg ;
+ m_numExtendedReq++ ;
+ break ;
+ case( MessageTypeEnum.MODDNREQUEST_VAL ):
+ m_lastModDNReq = a_msg ;
+ m_numModDNReq++ ;
+ break ;
+ case( MessageTypeEnum.MODIFYREQUEST_VAL ):
+ m_lastModifyReq = a_msg ;
+ m_numModifyReq++ ;
+ break ;
+ case( MessageTypeEnum.SEARCHREQUEST_VAL ):
+ m_lastSearchReq = a_msg ;
+ m_numSearchReq++ ;
+ break ;
+ case( MessageTypeEnum.UNBINDREQUEST_VAL ):
+ m_lastUnbindReq = a_msg ;
+ m_numUnbindReq++ ;
+ break ;
+ default:
+ throw new RuntimeException("Unknown LDAP message type.") ;
+ }
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/UnbindHandler.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/UnbindHandler.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,97 @@
+/*
+ * $Id: UnbindHandler.java,v 1.2 2003/08/22 21:15:56 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.protocol ;
+
+
+import org.apache.ldap.common.message.Request ;
+import org.apache.ldap.common.message.UnbindRequest ;
+import org.apache.ldap.common.message.MessageTypeEnum ;
+
+/**
+ * Handles the processing of UnbindRequests. Not presently implemented.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.2 $
+ */
+public class UnbindHandler
+ implements NoReplyHandler
+{
+ /** Reference to the protocol module this handler is part of */
+ private final ProtocolModule m_module ;
+
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Creates a handler for UnbindRequests to work on behalf of a
+ * ProtocolModule.
+ *
+ * @param a_module the ProtocolModule this handler is part of.
+ */
+ public UnbindHandler( ProtocolModule a_module )
+ {
+ m_module = a_module ;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // RequestHandler Interface Method Implementations
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Gets the handler type for this handler which will always be the
+ * HandlerTypeEnum.NOREPLY enumeration constant.
+ *
+ * @return the HandlerTypeEnum.NOREPLY enumeration constant
+ */
+ public final HandlerTypeEnum getHandlerType()
+ {
+ return HandlerTypeEnum.NOREPLY ;
+ }
+
+
+ /**
+ * Gets the message type handled by this handler which will always be the
+ * MessageTypeEnum.UNBINDREQUEST enumeration constant.
+ *
+ * @return the MessageTypeEnum.UNBINDREQUEST enumeration constant
+ */
+ public MessageTypeEnum getRequestType()
+ {
+ return MessageTypeEnum.UNBINDREQUEST ;
+ }
+
+
+ /**
+ * Handles an unbind request by disconnecting a client and terminating their
+ * session on the server.
+ *
+ * @param a_request the UnbindRequest.
+ * @throws ClassCastException if the a_request argument is not an
+ * UnbindRequest
+ */
+ public void handle( Request a_request )
+ {
+ try
+ {
+ UnbindRequest l_request = ( UnbindRequest) a_request ;
+ m_module.getClientManager().drop() ;
+ }
+ catch( Throwable t )
+ {
+ m_module.getLogger().error( "Failed on UnbindRequest!", t ) ;
+ }
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/Utils.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/Utils.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,590 @@
+/*
+ * $Id: Utils.java,v 1.2 2003/08/22 21:15:56 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.protocol;
+
+
+import java.util.Hashtable ;
+
+import javax.naming.Name ;
+import javax.naming.Context ;
+import javax.naming.NameParser ;
+import javax.naming.InitialContext ;
+import javax.naming.NamingException ;
+import javax.naming.ldap.LdapContext ;
+
+import org.apache.ldap.common.name.LdapName ;
+import org.apache.ldap.common.message.LdapResult ;
+import org.apache.ldap.common.message.ResultResponse ;
+import org.apache.ldap.common.message.ResultCodeEnum ;
+import org.apache.ldap.common.message.LdapResultImpl ;
+
+import org.apache.avalon.framework.ExceptionUtil ;
+import org.apache.avalon.framework.logger.Logger ;
+
+
+/**
+ * Utility functions used internally within this package by the protocol
+ * engine's handlers.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.2 $
+ */
+class Utils
+{
+ private static Logger s_log ;
+
+
+
+ // ------------------------------------------------------------------------
+ // Package Friendly Utility Methods Used By RequestHandlers
+ // ------------------------------------------------------------------------
+
+
+ static void enableLogging( Logger a_logger )
+ {
+ s_log = a_logger ;
+ }
+
+
+ static Logger getLogger()
+ {
+ return s_log ;
+ }
+
+
+ /**
+ * Gets the javax.naming.Name respresent a distinguished name provided as
+ * a String.
+ *
+ * @param a_dn the distinguished name String.
+ * @return the Name representing the String argument.
+ */
+ static Name getName( String a_dn )
+ throws NamingException
+ {
+ if( a_dn == null || a_dn.trim().equals( "" ) )
+ {
+ return new LdapName() ;
+ }
+
+ InitialContext l_ctx = new InitialContext() ;
+ NameParser l_parser = l_ctx.getNameParser( a_dn ) ;
+ return l_parser.parse( a_dn ) ;
+ }
+
+
+ /**
+ * Attempts to deduce the result code from a prefix within the error message
+ * of the throwable argument. Defaults to OPERATIONSERROR if no result code
+ * can be resolved.
+ *
+ * @param a_response the ResultResponse object to build the result for
+ * @param a_dn the dn associated with the request used to find the
+ * matchingDn for the response.
+ * @param t the throwable if any associated with the result.
+ */
+ static void setResult( ResultResponse a_response, String a_dn, Throwable t )
+ {
+ setResult( a_response, getResultCode( t ), a_dn, t ) ;
+ }
+
+
+ /**
+ * Attempts to deduce the result code from a prefix within the error message
+ * of the throwable argument. Defaults to OPERATIONSERROR if no result code
+ * can be resolved.
+ *
+ * @param a_response the ResultResponse object to build the result for
+ * @param a_dn the dn associated with the request used to find the
+ * matchingDn for the response.
+ * @param t the throwable if any associated with the result.
+ */
+ static void setResult( ResultResponse a_response, Name a_dn, Throwable t )
+ {
+ setResult( a_response, getResultCode( t ), a_dn, null, t, true ) ;
+ }
+
+
+ /**
+ * Overload used for successful results.
+ *
+ * @param a_response the ResultResponse object to build the result for
+ * @param a_dn the dn associated with the request used to find the
+ * matchingDn for the response.
+ */
+ static void setResult( ResultResponse a_response, Name a_dn )
+ {
+ setResult( a_response, ResultCodeEnum.SUCCESS, a_dn,
+ null, null, true ) ;
+ }
+
+
+ /**
+ * Overload used for successful results.
+ *
+ * @param a_response the ResultResponse object to build the result for
+ * @param a_dn the dn associated with the request used to find the
+ * matchingDn for the response.
+ */
+ static void setResult( ResultResponse a_response, String a_dn )
+ {
+ setResult( a_response, ResultCodeEnum.SUCCESS, a_dn,
+ null, null, true ) ;
+ }
+
+
+ /**
+ * Overload used for successful results.
+ *
+ * @param a_response the ResultResponse object to build the result for
+ * @param a_dn the dn associated with the request used to find the
+ * matchingDn for the response.
+ * @param a_matchForDn whether or not to resolve a matching dn - if false
+ * then a_dn is used as is.
+ */
+ static void setResult( ResultResponse a_response, Name a_dn,
+ boolean a_matchForDn )
+ {
+ setResult( a_response, ResultCodeEnum.SUCCESS, a_dn,
+ null, null, true ) ;
+ }
+
+
+ /**
+ * Overload used for successful results.
+ *
+ * @param a_response the ResultResponse object to build the result for
+ * @param a_dn the dn associated with the request used to find the
+ * matchingDn for the response.
+ * @param a_matchForDn whether or not to resolve a matching dn - if false
+ * then a_dn is used as is.
+ */
+ static void setResult( ResultResponse a_response, String a_dn,
+ boolean a_matchForDn )
+ {
+ setResult( a_response, ResultCodeEnum.SUCCESS, a_dn,
+ null, null, true ) ;
+ }
+
+
+ /**
+ * Utility function that creates and populates an LdapResult into a
+ * ResultResponse. So many places used this same code we had to put
+ * the it into one place as a utility function.
+ *
+ * @param a_response the ResultResponse object to build the result for
+ * @param a_resultCode the returned error code.
+ * @param a_dn the dn associated with the request used to find the
+ * matchingDn for the response.
+ * @param a_msg the error message to use.
+ */
+ static void setResult( ResultResponse a_response,
+ ResultCodeEnum a_resultCode, Name a_dn, String a_msg )
+ {
+ setResult( a_response, a_resultCode, a_dn, a_msg, null, true ) ;
+ }
+
+
+ /**
+ * Utility function that creates and populates an LdapResult into a
+ * ResultResponse. So many places used this same code we had to put
+ * the it into one place as a utility function.
+ *
+ * @param a_response the ResultResponse object to build the result for
+ * @param a_resultCode the returned error code.
+ * @param a_dn the dn associated with the request used to find the
+ * matchingDn for the response.
+ * @param a_msg the error message to use.
+ */
+ static void setResult( ResultResponse a_response,
+ ResultCodeEnum a_resultCode, String a_dn, String a_msg )
+ {
+ setResult( a_response, a_resultCode, a_dn, a_msg, null, true ) ;
+ }
+
+
+ /**
+ * Utility function that creates and populates an LdapResult into a
+ * ResultResponse when the matched Dn is unknown or irrelavent.
+ *
+ * @param a_response the ResultResponse object to build the result for
+ * @param a_resultCode the returned error code.
+ * @param a_msg the error message to use.
+ * @param t the throwable if any associated with the result.
+ */
+ static void setResult( ResultResponse a_response,
+ ResultCodeEnum a_resultCode, String a_msg, Throwable t )
+ {
+ setResult( a_response, a_resultCode, "", a_msg, t, true ) ;
+ }
+
+
+ /**
+ * Utility function that creates and populates an LdapResult into a
+ * ResultResponse. So many places used this same code we had to put
+ * the it into one place as a utility function.
+ *
+ * @param a_response the ResultResponse object to build the result for
+ * @param a_resultCode the returned error code.
+ * @param a_dn the dn associated with the request used to find the
+ * matchingDn for the response.
+ * @param a_msg the error message to use.
+ * @param t the throwable if any associated with the result.
+ */
+ static void setResult( ResultResponse a_response,
+ ResultCodeEnum a_resultCode, String a_dn, String a_msg, Throwable t )
+ {
+ setResult( a_response, a_resultCode, a_dn, a_msg, t, true ) ;
+ }
+
+
+ /**
+ * Utility function that creates and populates an LdapResult into a
+ * ResultResponse. So many places used this same code we had to put
+ * the it into one place as a utility function.
+ *
+ * @param a_response the ResultResponse object to build the result for
+ * @param a_resultCode the returned error code.
+ * @param a_dn the dn associated with the request used to find the
+ * matchingDn for the response.
+ * @param a_msg the error message to use.
+ * @param t the throwable if any associated with the result.
+ * @param a_matchForDn whether or not we attempt to find a matching dn for
+ * a_dn.
+ */
+ static void setResult( ResultResponse a_response,
+ ResultCodeEnum a_resultCode, String a_dn, String a_msg, Throwable t,
+ boolean a_matchForDn )
+ {
+ // Initialize the result object and set it in the response
+ LdapResult l_result = new LdapResultImpl( a_response ) ;
+ a_response.setLdapResult( l_result ) ;
+
+ // Log the error if this result is associated with a non null Throwable,
+ // error message and is not a part of a successful response.
+ if( t != null && a_msg != null &&
+ a_resultCode != ResultCodeEnum.SUCCESS )
+ {
+ getLogger().error( a_msg, t ) ;
+ }
+
+ // Do no error message if all is null
+ if( a_msg == null && t == null )
+ {
+ l_result.setErrorMessage( "" ) ;
+ }
+ // Use a_msg in error message if throwable is null only
+ else if( t == null && a_msg != null )
+ {
+ l_result.setErrorMessage( a_msg ) ;
+ }
+ // Use the stack trace as error message if a_msg is null and debug is on
+ else if( a_msg == null && t != null )
+ {
+ if( getLogger().isDebugEnabled() )
+ {
+ l_result.setErrorMessage( ExceptionUtil.printStackTrace( t ) ) ;
+ }
+ }
+ // When a_msg and t are not null
+ else
+ {
+ // Only append stack trace if debugging is enabled
+ if( getLogger().isDebugEnabled() )
+ {
+ l_result.setErrorMessage( a_msg
+ + ExceptionUtil.printStackTrace( t ) ) ;
+ }
+ // Do not append stack trace if debugging is off
+ else
+ {
+ l_result.setErrorMessage( a_msg ) ;
+ }
+ }
+
+
+ l_result.setResultCode( a_resultCode ) ;
+
+ if( a_dn == null )
+ {
+ a_dn = "" ;
+ }
+
+ try
+ {
+ if( a_matchForDn )
+ {
+ Name l_matchedDn = getMatchedDn( a_dn ) ;
+ l_result.setMatchedDn( l_matchedDn.toString() ) ;
+ }
+ else
+ {
+ l_result.setMatchedDn( a_dn ) ;
+ }
+ }
+ // Regardless of exception this is an operational error
+ catch( Exception e )
+ {
+ StringBuffer l_buf = new StringBuffer() ;
+ l_buf.append( "Could not find matching Dn for '" ) ;
+ l_buf.append( a_dn ) ;
+ l_buf.append( "' due to operational error: " ) ;
+ l_buf.append( e.getMessage() ) ;
+ String l_msg = l_buf.toString() ;
+
+ l_result.setMatchedDn( "" ) ;
+ l_result.setErrorMessage( l_msg ) ;
+ l_result.setResultCode( ResultCodeEnum.OPERATIONSERROR ) ;
+ getLogger().error( l_msg, e ) ;
+ }
+ }
+
+
+ /**
+ * Utility function that creates and populates an LdapResult into a
+ * ResultResponse. So many places used this same code we had to put
+ * the it into one place as a utility function.
+ *
+ * @param a_response the ResultResponse object to build the result for
+ * @param a_resultCode the returned error code.
+ * @param a_dn the dn associated with the request used to find the
+ * matchingDn for the response.
+ * @param a_msg the error message to use.
+ * @param t the throwable if any associated with the result.
+ */
+ static void setResult( ResultResponse a_response,
+ ResultCodeEnum a_resultCode, Name a_dn, String a_msg,
+ Throwable t, boolean a_matchForDn )
+ {
+ if( a_dn == null )
+ {
+ setResult( a_response, a_resultCode, "", a_msg, t, a_matchForDn ) ;
+ }
+ else
+ {
+ setResult( a_response, a_resultCode, a_dn.toString(), a_msg,
+ t, a_matchForDn ) ;
+ }
+ }
+
+
+ /**
+ * Utility method to get ahold of an ldap context based on a DN.
+ *
+ * @param a_dn the distinguished name of the ldap entry to get a JNDI context to.
+ * @return the context associated with an entry specified by dn.
+ */
+ static LdapContext getContext( String a_dn )
+ throws NamingException
+ {
+ return getContext( getName( a_dn ) ) ;
+ }
+
+
+ /**
+ * Utility method to get ahold of an ldap context based on a DN.
+ *
+ * @param a_dn the distinguished name of the ldap entry to get a JNDI context to.
+ * @return the context associated with an entry specified by dn.
+ */
+ static LdapContext getContext( Name a_dn )
+ throws NamingException
+ {
+ Hashtable l_env = new Hashtable() ;
+ InitialContext l_initialContext = null ;
+
+ l_env.put( Context.INITIAL_CONTEXT_FACTORY,
+ "org.apache.eve.jndi.ServerContextFactory" ) ;
+ l_initialContext = new InitialContext( l_env ) ;
+ return ( LdapContext ) l_initialContext.lookup( a_dn ) ;
+ }
+
+
+ /**
+ * Utility method to get then initial context.
+ *
+ * @return the initial context for the directory.
+ */
+ static InitialContext getInitialContext()
+ throws NamingException
+ {
+ Hashtable l_env = new Hashtable() ;
+ l_env.put( Context.INITIAL_CONTEXT_FACTORY,
+ "org.apache.eve.jndi.ServerContextFactory" ) ;
+ return new InitialContext( l_env ) ;
+ }
+
+
+ /**
+ * Gets the most significant Dn that exists within the server and hence can
+ * be matched to an actual entry.
+ *
+ * @param a_dn to use for the matching test.
+ * @return the matching portion of a_dn, or the valid empty string dn if no
+ * match was found.
+ */
+ static Name getMatchedDn( String a_dn )
+ throws NamingException
+ {
+ Name l_dn = null ;
+ Context l_ctx = null ;
+ InitialContext l_initCtx = null ;
+
+ // Don't try to match for the empty dn which matches by default
+ if( a_dn == null || a_dn.trim().equals( "" ) )
+ {
+ return new LdapName() ;
+ }
+
+ l_initCtx = getInitialContext() ;
+ l_dn = l_initCtx.getNameParser( a_dn ).parse( a_dn ) ;
+ while( l_dn.size() > 0 )
+ {
+ try
+ {
+ l_ctx = ( Context ) l_initCtx.lookup( l_dn ) ;
+ }
+ catch( NamingException ne )
+ {
+ // Ignore exceptions
+ }
+
+ if( l_ctx == null )
+ {
+ l_dn.remove( l_dn.size()-1 ) ;
+ }
+ else
+ {
+ return l_dn ;
+ }
+ }
+
+ return l_dn ;
+ }
+
+
+ /**
+ * Gets the most significant Dn that exists within the server and hence can
+ * be matched to an actual entry.
+ *
+ * @param a_dn to use for the matching test.
+ * @return the matching portion of a_dn, or the valid empty string dn if no
+ * match was found.
+ */
+ static Name getMatchedDn( Name a_dn )
+ throws NamingException
+ {
+ Name l_dn = ( Name ) a_dn.clone() ;
+ Context l_ctx = null ;
+ InitialContext l_initCtx = null ;
+
+ // Don't try to match for the empty dn which matches by default
+ if( l_dn.size() == 0 )
+ {
+ return l_dn ;
+ }
+
+ l_initCtx = getInitialContext() ;
+ while( l_dn.size() > 0 )
+ {
+ try
+ {
+ l_ctx = ( Context ) l_initCtx.lookup( l_dn ) ;
+ }
+ catch( NamingException ne )
+ {
+ // Ignore exceptions
+ }
+
+ if( l_ctx == null )
+ {
+ l_dn.remove( l_dn.size() - 1 ) ;
+ }
+ else
+ {
+ return l_dn ;
+ }
+ }
+
+ return l_dn ;
+ }
+
+
+ /**
+ * Gets the result code embedded within the message of a throwable. Because
+ * there is a loss of resolution in error codes due to many LDAPv3 result
+ * codes mapping to the same JNDI exception, we need to embed the result
+ * code associated with the error within the exception message. We cannot
+ * change the JNDI exception to add result code fields. So if the result
+ * code is embedded it is within the first four characters of the message.
+ * LDAPv3 result codes only go upto 80 so 2 digits are used at the most and
+ * single digit values are padded with zeros in the front. The '[' and ']'
+ * characters are used to delimit the result code value. So for example if
+ * the result code is a 51 for the BUSY result code then the message of the
+ * exception is prefixed with '[51]'. If the result code is a 3 for
+ * TIMELIMITEXCEEDED then the prefix would be '[03]'.
+ *
+ * Note that if the result code extraction process fails due to an number
+ * format exception on the failure to parse the integer value then the
+ * failure is logged as a warning and OPERATIONSERROR is returned. If the
+ * prefix does not exist it is presumed that the exception was due to an
+ * internal server failure that has no value other than OPERATIONSERROR
+ * associated with it. Unintentional exceptions not created and thrown by
+ * the code such as NullPointerExceptions hence result in OPERATIONSERRORS.
+ * And if debugging is enabled the entire stack trace eventually is
+ * delivered to the client with a request to report the bug.
+ *
+ * This method extracts the embedded result code string and parses it into
+ * an integer. It then calls the getResultCode(int) with the integer as the
+ * argument to get the ResultCodeEnum enumeration constant which it then
+ * returns.
+ *
+ * @param t the throwable carrying the embedded result code as a prefix
+ * @return the result code associated with the exception.
+ */
+ static ResultCodeEnum getResultCode( Throwable t )
+ {
+ String l_msg = t.getMessage() ;
+ ResultCodeEnum l_resultCode = null ;
+
+ // Don't try to extract the result code value if the message string is
+ // null or does not have the length to contain the prefix for the code
+ if( l_msg == null || l_msg.length() < 4 )
+ {
+ l_resultCode = ResultCodeEnum.OPERATIONSERROR ;
+ }
+ // Attempt to parse only if we have the starting and ending brackets
+ else if( l_msg.charAt( 0 ) == '[' && l_msg.charAt( 3 ) == ']' )
+ {
+ String l_code = l_msg.substring( 1, 3 ) ;
+
+ try
+ {
+ int l_enumValue = Integer.parseInt( l_code ) ;
+ l_resultCode = ResultCodeEnum.getResultCodeEnum( l_enumValue ) ;
+ }
+ catch( NumberFormatException nfe )
+ {
+ getLogger().warn( "Found embedded result code field of '"
+ + l_code + "' within error message however could not parse"
+ + " result code enumeration value from it." ) ;
+ l_resultCode = ResultCodeEnum.OPERATIONSERROR ;
+ }
+ }
+ // No prefix detected so we set the result code to OPERATIONSERROR
+ else
+ {
+ l_resultCode = ResultCodeEnum.OPERATIONSERROR ;
+ }
+
+ return l_resultCode ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/extended/PayloadHandler.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/protocol/extended/PayloadHandler.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,47 @@
+/*
+ * $Id: PayloadHandler.java,v 1.2 2003/08/22 21:15:56 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.protocol.extended ;
+
+
+import javax.naming.NamingException ;
+
+import org.apache.eve.backend.BackendException ;
+
+import org.apache.avalon.framework.logger.LogEnabled ;
+import org.apache.avalon.framework.service.Serviceable ;
+
+
+/**
+ * Interface used by all extended request payload handlers which are special
+ * handlers invoked by the ExtendedRequestHandler itself to deal with responding
+ * to an extended request with an extended response payload.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.2 $
+ */
+public interface PayloadHandler
+{
+ /**
+ * Gets the object identifier of the extended request this handler is
+ * designed for.
+ *
+ * @return the OID string.
+ */
+ String getRequestOID() ;
+
+ /**
+ * Handles the extended request by extracting parameters from the payload
+ * and optionally generating a response for the request.
+ */
+ byte [] handle( byte [] a_payload )
+ throws BackendException, NamingException ;
+}
+
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/schema/AttributeSpec.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/schema/AttributeSpec.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,126 @@
+/*
+ * $Id: AttributeSpec.java,v 1.4 2003/03/13 18:28:01 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.schema ;
+
+
+import java.util.ArrayList ;
+import java.util.Collection ;
+
+
+/**
+ * Attribute specification bean used to store the schema information for an
+ * attribute definition. This class is generated by the schema parser and
+ * populated in part by it during the schema file load phase. Other properties
+ * of the bean are filled in afterwords in other phases during the
+ * initialization of the schema manager.
+ */
+public class AttributeSpec
+{
+
+ //////////////////////////////
+ // Specification Attributes //
+ //////////////////////////////
+
+ String m_oid ;
+ ArrayList m_nameList = new ArrayList() ;
+ String m_desc ;
+ String m_equality ;
+ String m_substr ;
+ String m_ordering ;
+ String m_syntax ;
+ boolean m_isSingleValue = false ;
+ boolean m_canUserModify = true ;
+ String m_usage ;
+ String m_superClass ;
+
+ ////////////////////////////////////////
+ // Implementation Inferred Attributes //
+ ////////////////////////////////////////
+
+ /** Directly references other child AttributeSpecs */
+ ArrayList m_children = new ArrayList() ;
+
+ /**
+ * Gets the unique IANA registered Object IDentifier (OID) associated with
+ * this attribute specification.
+ *
+ * @return String the object identifier.
+ */
+ public String getOid()
+ {
+ return m_oid ;
+ }
+
+
+ public Collection getAllNames()
+ {
+ return m_nameList ;
+ }
+
+
+ public String getDescription()
+ {
+ return m_desc ;
+ }
+
+
+ public String getEqualityMatch()
+ {
+ return m_equality ;
+ }
+
+
+ public String getSubstrMatch()
+ {
+ return m_substr ;
+ }
+
+
+ public String getOrderingMatch()
+ {
+ return m_ordering ;
+ }
+
+
+ public String getSyntaxOid()
+ {
+ return m_syntax ;
+ }
+
+
+ public boolean isSingleValue()
+ {
+ return m_isSingleValue ;
+ }
+
+
+ public boolean canUserModify()
+ {
+ return m_canUserModify ;
+ }
+
+
+ public String getUsage()
+ {
+ return m_usage ;
+ }
+
+
+ public String getSuperClass()
+ {
+ return m_superClass ;
+ }
+
+
+ public String toString()
+ {
+ return m_oid ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/schema/Normalizer.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/schema/Normalizer.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,22 @@
+/*
+ * $Id: Normalizer.java,v 1.4 2003/03/13 18:28:02 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.schema ;
+import javax.naming.NamingException ;
+
+
+/**
+ * Equality matching rule attribute value normalizer.
+ */
+public interface Normalizer
+{
+ String getEqualityMatch() ;
+ String normalize(String a_value)
+ throws NamingException ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/schema/ObjectClassSpec.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/schema/ObjectClassSpec.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,101 @@
+/*
+ * $Id: ObjectClassSpec.java,v 1.4 2003/03/13 18:28:03 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+package org.apache.eve.schema ;
+
+
+import java.util.Collection ;
+import java.util.ArrayList ;
+
+
+/**
+ * Objectclass specification bean used to store the schema information for an
+ * objectclass definition. This class is generated by the schema parser and
+ * populated in part by it during the schema file load phase. Other properties
+ * of the bean are filled in afterwords in other phases during the
+ * initialization of the schema manager.
+ */
+public class ObjectClassSpec
+{
+ public static final int ABSTRACT = 0 ;
+ public static final int AUXILIARY = 1 ;
+ public static final int STRUCTURAL = 2 ;
+
+ /////////////////////////////
+ // Specification Variables //
+ /////////////////////////////
+
+ int type = ABSTRACT ;
+ String oid ;
+ String desc ;
+ ArrayList mayList = new ArrayList() ;
+ ArrayList mustList = new ArrayList() ;
+ ArrayList nameList = new ArrayList() ;
+ ArrayList superClasses = new ArrayList() ;
+
+ //////////////////////////////
+ // Implementation Variables //
+ //////////////////////////////
+
+ /** Directly references other child ObjectClassSpecs */
+ ArrayList m_children = new ArrayList() ;
+
+
+ public String getDesc()
+ {
+ return desc ;
+ }
+
+
+ public Collection getSuperClasses()
+ {
+ return superClasses ;
+ }
+
+
+ public int getType()
+ {
+ return type ;
+ }
+
+
+ public Collection getMustList()
+ {
+ return mustList ;
+ }
+
+
+ public Collection getMayList()
+ {
+ return mayList ;
+ }
+
+
+ public String getOid()
+ {
+ return oid ;
+ }
+
+
+ public Collection getNameList()
+ {
+ return nameList ;
+ }
+
+
+ public Collection getAllNames()
+ {
+ return nameList ;
+ }
+
+
+ public String toString()
+ {
+ return (String) nameList.get(0) ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/schema/ParserSyntaxChecker.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/schema/ParserSyntaxChecker.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,80 @@
+/*
+ * $Id: ParserSyntaxChecker.java,v 1.4 2003/08/22 21:15:56 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.schema ;
+import antlr.Parser ;
+import antlr.ANTLRLexer ;
+import java.io.StringReader ;
+import java.lang.reflect.Constructor ;
+import org.apache.avalon.framework.logger.AbstractLogEnabled ;
+import java.io.Reader ;
+
+
+public class ParserSyntaxChecker
+ extends AbstractLogEnabled
+ implements SyntaxChecker
+{
+ private final String m_syntaxOid ;
+ private Constructor m_lexerConstructor ;
+ private Constructor m_parserConstructor ;
+
+
+ public ParserSyntaxChecker(String a_syntaxOid,
+ Class a_lexerClass, Class a_parserClass)
+ {
+ m_syntaxOid = a_syntaxOid ;
+ Constructor [] l_constructors = a_lexerClass.getConstructors() ;
+ Constructor l_constructor = null ;
+
+ for(int ii = 0; ii < l_constructors.length ; ii++) {
+ l_constructor = l_constructors[ii] ;
+ Class [] params = l_constructor.getParameterTypes() ;
+
+ if(1 == params.length && params[0].equals(Reader.class)) {
+ m_lexerConstructor = l_constructor ;
+ break ;
+ }
+ }
+
+ l_constructors = a_parserClass.getConstructors() ;
+ for(int ii = 0; ii < l_constructors.length ; ii++) {
+ l_constructor = l_constructors[ii] ;
+ Class [] params = l_constructor.getParameterTypes() ;
+
+ if(1 == params.length && params[0].equals(a_lexerClass)) {
+ m_parserConstructor = l_constructor ;
+ break ;
+ }
+ }
+ }
+
+
+ public String getSyntaxOid()
+ {
+ return m_syntaxOid ;
+ }
+
+
+ public boolean isValidSyntax(String a_value)
+ {
+ try {
+ StringReader l_in = new StringReader(a_value) ;
+ Object [] args = new Object[1] ;
+ args[0] = l_in ;
+ ANTLRLexer l_lexer = (ANTLRLexer)
+ m_lexerConstructor.newInstance(args) ;
+ args[0] = l_lexer ;
+ Parser l_parser = (Parser) m_parserConstructor.newInstance(args) ;
+ // Ok we do not know what to do with this yet!
+ } catch(Exception e) {
+ }
+
+ throw new RuntimeException("N O T I M P L E M E N T E D Y E T !") ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/schema/RegexNormalizer.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/schema/RegexNormalizer.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,54 @@
+/*
+ * $Id: RegexNormalizer.java,v 1.4 2003/03/13 18:28:05 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+package org.apache.eve.schema ;
+
+import org.apache.oro.text.perl.Perl5Util ;
+
+
+public class RegexNormalizer
+ implements Normalizer
+{
+ final Perl5Util m_perl = new Perl5Util() ;
+ final String [] m_exprArray ;
+ final String m_equalMatch ;
+
+
+ public RegexNormalizer(String an_equalMatch, String [] a_exprArray)
+ {
+ m_equalMatch = an_equalMatch ;
+ m_exprArray = a_exprArray ;
+ }
+
+
+ public String normalize(final String a_value)
+ {
+ String l_canonical = a_value ;
+
+ for(int ii = 0; ii < m_exprArray.length; ii++) {
+ l_canonical = m_perl.substitute(m_exprArray[ii], l_canonical) ;
+ }
+
+ return l_canonical ;
+ }
+
+
+ public String getEqualityMatch()
+ {
+ return m_equalMatch ;
+ }
+
+
+ public String toString()
+ {
+ StringBuffer l_buf = new StringBuffer() ;
+ l_buf.append("RegexNormalizer(").append(m_equalMatch).append(", ") ;
+ l_buf.append(m_exprArray).append(')') ;
+ return l_buf.toString() ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/schema/RegexSyntaxChecker.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/schema/RegexSyntaxChecker.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,50 @@
+/*
+ * $Id: RegexSyntaxChecker.java,v 1.3 2003/03/13 18:28:05 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.schema ;
+
+
+import org.apache.oro.text.perl.Perl5Util ;
+
+
+public class RegexSyntaxChecker
+ implements SyntaxChecker
+{
+ private final String m_syntaxOid ;
+ private final String [] m_expressions ;
+ private final Perl5Util m_perl = new Perl5Util() ;
+
+
+ public RegexSyntaxChecker(String a_syntaxOid, String [] a_matchExprArray)
+ {
+ m_expressions = a_matchExprArray ;
+ m_syntaxOid = a_syntaxOid ;
+ }
+
+
+ public String getSyntaxOid()
+ {
+ return m_syntaxOid ;
+ }
+
+
+ public boolean isValidSyntax(String a_value)
+ {
+ boolean l_match = true ;
+
+ for(int ii = 0; ii < m_expressions.length; ii++) {
+ l_match = l_match && m_perl.match(m_expressions[ii], a_value) ;
+ if(!l_match) {
+ break ;
+ }
+ }
+
+ return l_match ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/schema/Schema.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/schema/Schema.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,62 @@
+/*
+ * $Id: Schema.java,v 1.10 2003/08/06 04:34:18 akarasulu Exp $
+ * $Prologue$
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.schema ;
+
+
+import java.util.Map ;
+import java.util.HashMap ;
+
+import javax.naming.NameParser ;
+import javax.naming.NamingException ;
+import javax.naming.directory.SchemaViolationException ;
+import javax.naming.directory.InvalidAttributesException ;
+
+import org.apache.ldap.common.ldif.LdifParser ;
+import org.apache.ldap.common.ldif.LdifComposer ;
+import org.apache.eve.backend.LdapEntry ;
+
+
+/**
+ * Primitive representation of a schem interface from the perspective of a
+ * backend.
+ */
+public interface Schema
+{
+ String DN_ATTR = "distinguishedname" ;
+ String EXISTANCE_ATTR = "existance" ;
+ String HIERARCHY_ATTR = "parentid" ;
+
+ Map BINARY_SYNTAX_OIDS = new HashMap() ;
+ Map NUMERIC_SYNTAX_OIDS = new HashMap() ;
+ Map DECIMAL_SYNTAX_OIDS = new HashMap() ;
+
+ String normalize( String an_attributeName, String an_attributeValue )
+ throws NamingException ;
+ Normalizer getNormalizer( String a_key, boolean byName )
+ throws NamingException ;
+ void check( LdapEntry an_entry )
+ throws SchemaViolationException, InvalidAttributesException ;
+
+ boolean isOperational( String an_attributeName ) ;
+ boolean isMultiValue( String an_attributeName ) ;
+ boolean isSingleValue( String an_attributeName ) ;
+ boolean hasAttribute( String an_attributeName ) ;
+ boolean isValidSyntax( String an_attributeName, Object an_attributeValue ) ;
+ boolean isValidSyntax( String an_attributeName,
+ Object [] an_attributeValue ) ;
+ boolean isBinary( String an_attributeName ) ;
+ boolean isNumeric( String an_attributeName ) ;
+ boolean isDecimal( String an_attributeName ) ;
+ NameParser getNameParser() ;
+ NameParser getNormalizingParser() ;
+ LdifParser getLdifParser() ;
+ LdifComposer getLdifComposer() ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/schema/SchemaImpl.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/schema/SchemaImpl.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,578 @@
+/*
+ * $Id: SchemaImpl.java,v 1.14 2003/08/06 04:34:18 akarasulu Exp $
+ * $Prologue$
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.schema ;
+
+
+import org.apache.eve.schema.Schema ;
+import org.apache.eve.backend.LdapEntry ;
+import org.apache.ldap.common.ldif.LdifParser ;
+import org.apache.ldap.common.ldif.LdifParserImpl ;
+import org.apache.ldap.common.ldif.LdifComposer ;
+import org.apache.ldap.common.ldif.LdifComposerImpl ;
+
+import javax.naming.NameParser ;
+import javax.naming.directory.SchemaViolationException ;
+import javax.naming.directory.InvalidAttributesException ;
+
+import java.util.Map ;
+import java.util.HashMap ;
+import java.util.Iterator ;
+
+import org.apache.commons.collections.MultiMap ;
+import org.apache.commons.collections.MultiHashMap ;
+import org.apache.avalon.framework.logger.AbstractLogEnabled;
+import javax.naming.NamingException;
+import org.apache.ldap.common.name.NameComponentNormalizer;
+import org.apache.ldap.common.name.DnParser;
+import java.io.IOException;
+import org.apache.avalon.framework.CascadingRuntimeException;
+
+
+/**
+ * A quick and dirty schema implementation.
+ */
+public class SchemaImpl
+ extends AbstractLogEnabled
+ implements Schema
+{
+ public static boolean debug = false ;
+
+ static {
+ // Octet String
+ BINARY_SYNTAX_OIDS.put("1.3.6.1.4.1.1466.115.121.1.40",
+ "1.3.6.1.4.1.1466.115.121.1.40") ;
+ // Certificate Pair
+ BINARY_SYNTAX_OIDS.put("1.3.6.1.4.1.1466.115.121.1.10",
+ "1.3.6.1.4.1.1466.115.121.1.10") ;
+ // JPEG File Interchange Format JFIF
+ BINARY_SYNTAX_OIDS.put("1.3.6.1.4.1.1466.115.121.1.28",
+ "1.3.6.1.4.1.1466.115.121.1.28") ;
+ // Binary
+ BINARY_SYNTAX_OIDS.put("1.3.6.1.4.1.1466.115.121.1.5",
+ "1.3.6.1.4.1.1466.115.121.1.5") ;
+ // Certificate
+ BINARY_SYNTAX_OIDS.put("1.3.6.1.4.1.1466.115.121.1.8",
+ "1.3.6.1.4.1.1466.115.121.1.8") ;
+ // Certificate List
+ BINARY_SYNTAX_OIDS.put("1.3.6.1.4.1.1466.115.121.1.9",
+ "1.3.6.1.4.1.1466.115.121.1.9") ;
+ // Authentication Password Syntax
+ // (Not all binary but we can treat it as such)
+ BINARY_SYNTAX_OIDS.put("1.3.6.1.4.1.4203.1.1.2",
+ "1.3.6.1.4.1.4203.1.1.2") ;
+
+ // INTEGER 1.3.6.1.4.1.1466.115.121.1.27
+ NUMERIC_SYNTAX_OIDS.put("1.3.6.1.4.1.1466.115.121.1.27",
+ "1.3.6.1.4.1.1466.115.121.1.27") ;
+ // Numeric String 1.3.6.1.4.1.1466.115.121.1.36
+ NUMERIC_SYNTAX_OIDS.put("1.3.6.1.4.1.1466.115.121.1.36",
+ "1.3.6.1.4.1.1466.115.121.1.36") ;
+ }
+
+ Map m_syntaxCheckers = new HashMap() ;
+ Map m_normalizers = new HashMap() ;
+
+ LdifComposer m_ldifComposer = new LdifComposerImpl() ;
+ LdifParser m_ldifParser = new LdifParserImpl() ;
+
+ Map m_attributeByOid = new HashMap() ;
+ Map m_attributeByName = new HashMap() ;
+
+ Map m_attribute2super = new HashMap() ;
+
+ MultiMap m_attribute2objectclass = new MultiHashMap() ;
+ MultiMap m_attribute2subordinates = new MultiHashMap() ;
+
+ Map m_objectClassByName = new HashMap() ;
+ Map m_objectClassByOid = new HashMap() ;
+
+ MultiMap m_objectClass2super = new MultiHashMap() ;
+ MultiMap m_objectClass2subordinates = new MultiHashMap() ;
+
+ DnParser m_normalizingParser = null ;
+ DnParser m_parser = null ;
+
+ /////////////////
+ // Constructor //
+ /////////////////
+
+
+ SchemaImpl()
+ {
+ NameComponentNormalizer l_dnNormalizer = new NameComponentNormalizer() {
+ public String normalizeByName(String a_name, String a_value)
+ throws NamingException
+ {
+ return getNormalizer(a_name, true).normalize(a_value) ;
+ }
+
+
+ public String normalizeByOid(String a_oid, String a_value)
+ throws NamingException
+ {
+ return getNormalizer(a_oid, false).normalize(a_value) ;
+ }
+ } ;
+
+ try {
+ m_parser = new DnParser() ;
+ m_normalizingParser = new DnParser(l_dnNormalizer) ;
+ } catch(IOException e) {
+ throw new CascadingRuntimeException("Could not initialize DnParser "
+ + "for SchemaImpl ", e) ;
+ }
+ }
+
+
+ //////////////////////
+ // Setup Interfaces //
+ //////////////////////
+
+
+ AttributeSpec getAttributeSpec(String a_key, boolean byName)
+ throws NamingException
+ {
+ AttributeSpec l_spec = null ;
+
+ if(byName) {
+ l_spec = (AttributeSpec) m_attributeByName.get(a_key) ;
+ } else {
+ l_spec = (AttributeSpec) m_attributeByOid.get(a_key) ;
+ }
+
+ if(l_spec == null) {
+ throw new NamingException("Unknown AttributeType "
+ + a_key) ;
+ }
+
+ return l_spec ;
+ }
+
+
+ void setNormalizers(HashMap a_map)
+ {
+ m_normalizers = a_map ;
+ }
+
+
+ void setSyntaxCheckers(HashMap a_map)
+ {
+ m_syntaxCheckers = a_map ;
+ }
+
+
+ Iterator listAttributeSpecs()
+ {
+ return m_attributeByOid.values().iterator() ;
+ }
+
+
+ Iterator listObjectClassSpecs()
+ {
+ return m_objectClassByOid.values().iterator() ;
+ }
+
+
+ void addSchema(SchemaImpl a_schema)
+ {
+ Iterator l_list = a_schema.listAttributeSpecs() ;
+ while(l_list.hasNext()) {
+ addAttributeSpec((AttributeSpec) l_list.next()) ;
+ }
+
+ l_list = a_schema.listObjectClassSpecs() ;
+ while(l_list.hasNext()) {
+ this.addObjectClassSpec((ObjectClassSpec) l_list.next()) ;
+ }
+ }
+
+
+ void addAttributeSpec(AttributeSpec an_attribute)
+ {
+ if(getLogger().isDebugEnabled() && debug) {
+ getLogger().debug("Adding attribute spec for " +
+ an_attribute.getAllNames()) ;
+ }
+
+ m_attributeByOid.put(an_attribute.getOid(), an_attribute) ;
+
+ Iterator l_list = an_attribute.getAllNames().iterator() ;
+ String l_name = null ;
+ String l_superClass = an_attribute.getSuperClass() ;
+
+ if(l_superClass != null) {
+ l_superClass = l_superClass.toLowerCase() ;
+
+ // Equality matching rule should be inherited by topmost superclass
+ // if not specified.
+ if(null == an_attribute.getEqualityMatch()) {
+ AttributeSpec l_superSpec =
+ (AttributeSpec) m_attributeByName.get(l_superClass) ;
+
+ if(l_superSpec == null) {
+ throw new RuntimeException("Attribute spec of super class '"
+ + l_superClass + "' for attribute '" + an_attribute
+ + "' was not found") ;
+ } else if(null == l_superSpec.m_equality) {
+ throw new RuntimeException("Super class " + l_superClass
+ + " of " + an_attribute + " does not have an equality "
+ + "matching rule") ;
+ } else {
+ an_attribute.m_equality = l_superSpec.m_equality ;
+ }
+ }
+ }
+
+ while(l_list.hasNext()) {
+ l_name = ((String) l_list.next()).toLowerCase() ;
+ m_attributeByName.put(l_name, an_attribute) ;
+
+ if(l_superClass != null) {
+ m_attribute2super.put(l_name, l_superClass) ;
+ m_attribute2subordinates.put(l_superClass, l_name) ;
+ }
+ }
+ }
+
+
+ void addObjectClassSpec(ObjectClassSpec an_objectClass)
+ {
+ if(getLogger().isDebugEnabled() && debug) {
+ getLogger().debug("Adding objectclass spec for " +
+ an_objectClass.getAllNames()) ;
+ }
+
+ try {
+ m_objectClassByOid.put(an_objectClass.getOid(), an_objectClass) ;
+
+ Iterator l_list = an_objectClass.getAllNames().iterator() ;
+ String l_name = null ;
+ Iterator l_superClasses =
+ an_objectClass.getSuperClasses().iterator() ;
+ String l_superClass = null ;
+ while(l_list.hasNext()) {
+ l_name = ((String) l_list.next()).toLowerCase() ;
+ m_objectClassByName.put(l_name, an_objectClass) ;
+
+ while(l_superClasses.hasNext()) {
+ l_superClass =
+ ((String) l_superClasses.next()).toLowerCase() ;
+ if(l_superClass != null) {
+ m_objectClass2super.put(l_name, l_superClass) ;
+ m_objectClass2subordinates.put(l_superClass, l_name) ;
+ }
+ }
+ }
+ } catch(Exception e) {
+ e.printStackTrace() ;
+ }
+ }
+
+
+ ///////////////////////
+ // Schema Interfaces //
+ ///////////////////////
+
+
+ public boolean isBinary(String an_attributeName)
+ {
+ AttributeSpec l_attribute = (AttributeSpec)
+ m_attributeByName.get(an_attributeName.toLowerCase()) ;
+ return BINARY_SYNTAX_OIDS.containsKey(l_attribute.getSyntaxOid()) ;
+ }
+
+
+ public boolean isNumeric(String an_attributeName)
+ {
+ AttributeSpec l_attribute = (AttributeSpec)
+ m_attributeByName.get(an_attributeName.toLowerCase()) ;
+ return NUMERIC_SYNTAX_OIDS.containsKey(l_attribute.getSyntaxOid()) ;
+ }
+
+
+ public boolean isDecimal(String an_attributeName)
+ {
+ AttributeSpec l_attribute = (AttributeSpec)
+ m_attributeByName.get(an_attributeName.toLowerCase()) ;
+ return DECIMAL_SYNTAX_OIDS.containsKey(l_attribute.getSyntaxOid()) ;
+ }
+
+
+ public LdifComposer getLdifComposer()
+ {
+ return m_ldifComposer ;
+ }
+
+ public LdifParser getLdifParser()
+ {
+ return m_ldifParser ;
+ }
+
+
+ public NameParser getNameParser()
+ {
+ return m_parser ;
+ }
+
+ public NameParser getNormalizingParser()
+ {
+ return m_normalizingParser ;
+ }
+
+
+ public Normalizer getNormalizer(String a_key, boolean byName)
+ throws NamingException
+ {
+ AttributeSpec l_spec = getAttributeSpec(a_key, byName) ;
+ String l_equalityMatch = l_spec.getEqualityMatch() ;
+ if(null == l_equalityMatch) {
+ throw new SchemaViolationException("Attribute " + a_key
+ + " does not have an equality matching rule in its spec") ;
+ }
+
+ /*
+ if(getLogger().isInfoEnabled()) {
+ getLogger().info("SchemaImpl.getNormalizer(): attribute '"
+ + a_key + "' with equality match '" + l_equalityMatch
+ + "' has the following normalizer '"
+ + m_normalizers.get(l_equalityMatch) + "'") ;
+ }
+ */
+
+ return (Normalizer) m_normalizers.get(l_equalityMatch) ;
+ }
+
+
+ public void check(LdapEntry an_entry)
+ throws SchemaViolationException, InvalidAttributesException
+ {
+ throw new RuntimeException("N O T I M P L E M E N T E D Y E T !") ;
+ }
+
+
+ public boolean hasAttribute(String an_attributeName)
+ {
+ return m_attributeByName.containsKey(an_attributeName.toLowerCase()) ;
+ }
+
+
+ public boolean isOperational( String an_attributeName )
+ {
+ /*
+ * There are two kinds of operational attributes:
+ * 1). Those defined by the protocol
+ * 2). Those defined by backends for their own use
+ *
+ * The schema and schema manager should only have to be aware of those
+ * operational attributes that are defined by the protocol. Backend
+ * specific attributes should be managed by the backend. Outside of the
+ * backend these attributes are just regular user attributes. The
+ * functionality of filtering out operational attributes on search
+ * entry responses is the job of both the backend and the search
+ * processing code. Each should do it for the attributes under its
+ * jurisdiction. Here we breach this sensible contract by having the
+ * schema manager be aware of backend operational attributes.
+ *
+ * TODO this method pretends to know about the special operational
+ * attributes used by the modjdbm backend and hence is imposing a
+ * dependency. The sooner operational or attribute filtering is
+ * implemented within the backend the better.
+ */
+
+ if (
+ an_attributeName.toLowerCase().equals( Schema.DN_ATTR ) ||
+ an_attributeName.toLowerCase().equals( Schema.HIERARCHY_ATTR ) ||
+ an_attributeName.toLowerCase().equals( "parentdn" ) ||
+ an_attributeName.toLowerCase().equals( "entryid" )
+ )
+ {
+ return true ;
+ }
+
+ AttributeSpec l_attribute = ( AttributeSpec )
+ m_attributeByName.get( an_attributeName.toLowerCase() ) ;
+
+ if ( l_attribute == null )
+ {
+ return false ;
+ }
+ else if ( l_attribute.getUsage() == null )
+ {
+ return false ;
+ }
+ else if ( l_attribute.getUsage().toLowerCase().equals( "directoryoperation" ) )
+ {
+ return true ;
+ }
+ else
+ {
+ return false ;
+ }
+ }
+
+
+ public boolean isMultiValue(String an_attributeName)
+ {
+ AttributeSpec l_attribute = (AttributeSpec)
+ m_attributeByName.get(an_attributeName.toLowerCase()) ;
+ return !l_attribute.isSingleValue() ;
+ }
+
+
+ public boolean isSingleValue(String an_attributeName)
+ {
+ AttributeSpec l_attribute = (AttributeSpec)
+ m_attributeByName.get(an_attributeName.toLowerCase()) ;
+ return l_attribute.isSingleValue() ;
+ }
+
+
+ public boolean isValidSyntax(String an_attributeName,
+ Object [] an_attributeValue)
+ {
+ // We need to create regular expressions for the various
+ // syntax types and use them to see if we match.
+ //throw new RuntimeException("N O T I M P L E M E N T E D Y E T !") ;
+
+ //getLogger().warn("N O T I M P L E M E N T E D Y E T :\n\t" +
+ // "SchemaImpl.isValidSyntax() ") ;
+ return true ;
+ }
+
+
+ public boolean isValidSyntax(String an_attributeName,
+ Object an_attributeValue)
+ {
+ // We need to create regular expressions for the various
+ // syntax types and use them to see if we match.
+ //throw new RuntimeException("N O T I M P L E M E N T E D Y E T !") ;
+
+ // getLogger().warn("N O T I M P L E M E N T E D Y E T :\n\t" +
+ // "SchemaImpl.isValidSyntax() ") ;
+ return true ;
+ }
+
+
+ public String normalize(String an_attributeName, String an_attributeValue)
+ throws NamingException
+ {
+ if(getLogger().isDebugEnabled() && debug) {
+ getLogger().debug("normalize called on attribute " +
+ an_attributeName + " with value " + an_attributeValue) ;
+ getLogger().debug("Normalizer map = " + m_normalizers) ;
+ }
+
+ AttributeSpec l_attribute = (AttributeSpec)
+ m_attributeByName.get(an_attributeName.toLowerCase()) ;
+
+ if(getLogger().isDebugEnabled() && an_attributeName.equals("parentId")
+ && debug)
+ {
+ getLogger().debug("Dumping attribute keys in schema") ;
+ Iterator l_list = m_attributeByName.keySet().iterator() ;
+ while(l_list.hasNext()) {
+ String l_name = (String) l_list.next() ;
+ if(l_name.startsWith("p"))
+ getLogger().debug(l_name) ;
+ }
+ }
+
+ if(getLogger().isDebugEnabled() && debug) {
+ getLogger().debug("spec for attribute " +
+ an_attributeName + " = " + l_attribute) ;
+ getLogger().debug("Equality Match Rule for attribute " +
+ an_attributeName + " = " + l_attribute.getEqualityMatch()) ;
+ }
+
+ String l_equalityMatch = l_attribute.getEqualityMatch() ;
+ if(null != l_equalityMatch) {
+ l_equalityMatch = l_equalityMatch.toLowerCase() ;
+ } else {
+ if(getLogger().isDebugEnabled() && debug) {
+ getLogger().debug("Equality matching rule not defined for "
+ + "attribute " + an_attributeName + " returning value '" +
+ an_attributeValue + "' as is") ;
+ }
+
+ return an_attributeValue ;
+ }
+
+ if(!m_normalizers.containsKey(l_equalityMatch)) {
+ if(getLogger().isDebugEnabled() && debug) {
+ getLogger().debug("Could not find normalizer for attribute "
+ + an_attributeName + " with equality matching rule "
+ + l_equalityMatch + " returning value '" +
+ an_attributeValue + "' as is") ;
+ getLogger().debug(getNormalizerDump()) ;
+ }
+ return an_attributeValue ;
+ }
+
+ Normalizer l_normalizer = (Normalizer)
+ m_normalizers.get(l_attribute.getEqualityMatch().toLowerCase()) ;
+ String l_canonical = l_normalizer.normalize(an_attributeValue) ;
+
+ if(getLogger().isDebugEnabled() && debug) {
+ getLogger().debug("Found normalizer for attribute "
+ + an_attributeName + " returning normalized value '" +
+ l_canonical + "'.") ;
+ }
+
+ return l_canonical ;
+ }
+
+ /** JUST FARTING AROUND */
+ public String toString()
+ {
+ String l_str = "\n\nAttribute Subordinates Map:\n\n"
+ + "==============================================================\n"
+ + m_attribute2subordinates.toString() + "\n\n"
+ + "Attribute SuperClass Map: "
+ + "==============================================================\n"
+ + m_attribute2super.toString() + "\n\n"
+ + "Attribute By Name Map: "
+ + "==============================================================\n"
+ + m_attributeByName.toString() + "\n\n"
+ + "Attribute By OID Map: "
+ + "==============================================================\n"
+ + m_attributeByOid.toString()
+ + "Object Class Subordinates Map:\n\n"
+ + "==============================================================\n"
+ + m_objectClass2subordinates.toString() + "\n\n"
+ + "Object Class SuperClass Map: "
+ + "==============================================================\n"
+ + m_objectClass2super.toString() + "\n\n"
+ + "Object Class By Name Map: "
+ + "==============================================================\n"
+ + m_objectClassByName.toString() + "\n\n"
+ + "Object Class By OID Map: "
+ + "==============================================================\n"
+ + m_objectClassByOid.toString() ;
+
+ return l_str ;
+ }
+
+
+ String getNormalizerDump()
+ {
+ StringBuffer l_buf = new StringBuffer() ;
+ l_buf.append("Normalizer Key Dump:\n") ;
+ Iterator l_list = m_normalizers.keySet().iterator() ;
+
+ while(l_list.hasNext()) {
+ l_buf.append("\t").append(l_list.next()).append("\n") ;
+ }
+
+ l_buf.append("\nDump Complete\n") ;
+
+ return l_buf.toString() ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/schema/SchemaManager.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/schema/SchemaManager.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,29 @@
+/*
+ * $Id: SchemaManager.java,v 1.3 2003/03/13 18:28:08 akarasulu Exp $
+ * $Prologue$
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.schema ;
+
+
+import javax.naming.NamingException ;
+import javax.naming.InvalidNameException ;
+import javax.naming.NameNotFoundException ;
+
+
+/**
+ * Manages schemas based on namespace.
+ */
+public interface SchemaManager
+{
+ public static final String ROLE = SchemaManager.class.getName() ;
+
+ Schema getSchema(String a_dn)
+ throws NamingException ;
+ Schema getCompleteSchema() ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/schema/SchemaModule.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/schema/SchemaModule.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,444 @@
+/*
+ * $Id: SchemaModule.java,v 1.12 2003/08/22 21:15:56 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.schema ;
+
+
+import java.io.File;
+import java.io.FileInputStream ;
+import java.io.FileNotFoundException ;
+
+import java.util.HashMap ;
+import java.util.Iterator ;
+
+import javax.naming.NamingException ;
+import javax.naming.NameNotFoundException ;
+
+import org.apache.eve.AbstractModule ;
+import org.apache.ldap.common.util.StringTools ;
+
+import antlr.RecognitionException ;
+import antlr.TokenStreamException ;
+
+import org.apache.avalon.phoenix.BlockContext ;
+import org.apache.avalon.framework.logger.Logger;
+import org.apache.avalon.framework.context.Context ;
+import org.apache.avalon.framework.context.ContextException ;
+import org.apache.avalon.framework.configuration.Configuration ;
+import org.apache.avalon.framework.configuration.ConfigurationException ;
+
+
+/**
+ * Schema manager module/block implementation used to parse schema files and
+ * manage DIB schemas and subschema authoritative areas.
+ *
+ * @phoenix:block
+ * @phoenix:service name="org.apache.eve.schema.SchemaManager"
+ * @testcase org.apache.eve.schema.TestSchemaModule
+ */
+public class SchemaModule
+ extends AbstractModule implements SchemaManager
+{
+ public static final String BLOCK_CONFIG_NODE = "schema-manager" ;
+
+ private BlockContext m_context ;
+ /** all schema definitions in one place */
+ private final SchemaImpl m_complete = new SchemaImpl() ;
+ /** syntax OID : SyntaxChecker */
+ private final HashMap m_syntaxCheckerMap = new HashMap() ;
+ /** equality matching rule : Normalizer */
+ private final HashMap m_normalizerMap = new HashMap() ;
+ /** schema name : SchemaImpl */
+ private final HashMap m_schemaFileMap = new HashMap() ;
+ /** suffix : SchemaImpl */
+ private final HashMap m_suffixSchemaMap = new HashMap() ;
+
+
+ public void enableLogging(Logger a_logger)
+ {
+ super.enableLogging(a_logger) ;
+ m_complete.enableLogging(a_logger) ;
+ }
+
+
+ public Schema getCompleteSchema()
+ {
+ return m_complete ;
+ }
+
+
+ public Schema getSchema(String a_dn)
+ throws NamingException
+ {
+ // Give it a try without wasting cycles.
+ if(m_suffixSchemaMap.containsKey(a_dn)) {
+ return (Schema) m_suffixSchemaMap.get(a_dn) ;
+ }
+
+ // Now normalize the DN and try again.
+ String l_canonical = m_complete.normalize(Schema.DN_ATTR, a_dn) ;
+ if(m_suffixSchemaMap.containsKey(a_dn)) {
+ return (Schema) m_suffixSchemaMap.get(a_dn) ;
+ }
+
+ throw new NameNotFoundException("No SAA matches suffix: " + a_dn) ;
+ }
+
+
+ public String getImplementationRole()
+ {
+ return ROLE ;
+ }
+
+
+ public String getImplementationName()
+ {
+ return "Schema Manager Module" ;
+ }
+
+
+ public String getImplementationClassName()
+ {
+ return SchemaModule.class.getName() ;
+ }
+
+
+ public void contextualize(Context a_context)
+ throws ContextException
+ {
+ super.contextualize(a_context) ;
+
+ try {
+ m_context = (BlockContext) a_context ;
+ if(getLogger().isDebugEnabled()) {
+ getLogger().debug("Got handle on block context with base "
+ + "directory "
+ + m_context.getBaseDirectory().getAbsolutePath()) ;
+ }
+ } catch(ClassCastException e) {
+ getLogger().debug("Context is not an instance of BlockContext!") ;
+ throw new ContextException(
+ "Context is not an instance of BlockContext!", e) ;
+ }
+ }
+
+
+ /*
+ =========================================
+ E X A M P L E C O N F I G U R A T I O N
+ =========================================
+
+ <toptag>
+ <!-- S T A G E : I -->
+ <!-- files are parsed first to build m_schemaFileMap -->
+
+ <schema name="core"
+ filepath="schema/core.schema" />
+ <schema name="corba"
+ filepath="schema/corba.schema" />
+ <schema name="cosine"
+ filepath="schema/cosine.schema" />
+ <schema name="java"
+ filepath="schema/java.schema" />
+ <schema name="misc"
+ filepath="schema/misc.schema" />
+ <schema name="nis"
+ filepath="schema/nis.schema" />
+ <schema name="krb5-kdc"
+ filepath="schema/krb5-kdc.schema" />
+ <schema name="inetorgperson"
+ filepath="schema/inetorgperson.schema" />
+
+ <!-- S T A G E : II -->
+ <!-- built-ins: deepTrimToLower, deepTrim, trim, dnNormalize, asis -->
+ <!-- regex version is perl5 -->
+
+ <normalization default="asis">
+ <normalizer op="deepTrimToLower" rule="caseIgnoreMatch"/>
+ <normalizer op="deepTrimToLower" rule="caseIgnoreListMatch"/>
+ <normalizer op="deepTrimToLower" rule="caseIgnoreIA5Match"/>
+ <normalizer op="deepTrim" rule="caseExactIA5Match"/>
+ <normalizer op="deepTrim" rule="telephoneNumberMatch"/>
+ <normalizer op="dnNormalize" rule="distinguishedNameMatch"/>
+
+ <normalizer rule="someNewBogusRule">
+ <regex value="s/abc/123/g"/>
+ <regex value="/ /d"/>
+ <regex value="y/def/DEF/"/>
+ </normalizer>
+ </normalization>
+
+ <!-- S T A G E : III -->
+ <!-- built-ins: accept, . . ., TBA -->
+ <!-- regex version is perl5 -->
+ <syntax-checkers default="accept">
+ <!-- fictitious: matches yes, Yes, YES etc -->
+ <syntax-checker oid="1.2.34.2.1.2.3.4523.1">
+ <regex value="/yes/i"/>
+ </syntax-checker>
+ </syntax-checkers>
+
+ <!-- S T A G E : IV -->
+ <!-- Subschema Administrative Area -->
+ <SAA dn="dc=sales,dc=example,dc=com">
+ <schema-ref schema="core"/>
+ <schema-ref schema="inetorgperson"/>
+ </SAA>
+
+ <!-- Subschema Administrative Area -->
+ <SAA dn="dc=engineering,dc=example,dc=com">
+ <schema-ref schema="core"/>
+ <schema-ref schema="cosine"/>
+ <schema-ref schema="corba"/>
+ <schema-ref schema="java"/>
+ <schema-ref schema="misc"/>
+ <schema-ref schema="inetorgperson"/>
+ </SAA>
+
+ <!-- Subschema Administrative Area -->
+ <SAA dn="nisDomain=unix,dc=example,dc=com">
+ <schema-ref schema="core"/>
+ <schema-ref schema="cosine"/>
+ <schema-ref schema="inetorgperson"/>
+ <schema-ref schema="nis"/>
+ </SAA>
+ </toptag>
+
+ */
+
+
+ public void configure(Configuration a_config)
+ throws ConfigurationException
+ {
+ //
+ // Right now the only way to add these files to the sar is via the
+ // <lib> or <classes> nexted sar directive in the ant build. This
+ // unfortunately packages the schema files under the
+ // apps/ldapd/SAR-INF/lib directory rather than at the top level.
+ //
+ // I tried to update the sar by using jar to add the schema directory
+ // and its contents to the top level directory but updates fail on jar.
+ //
+
+ String l_baseDir = m_context.getBaseDirectory().getAbsolutePath() ;
+ l_baseDir = l_baseDir + File.separator + "SAR-INF" + File.separator +
+ "lib" ;
+
+ // Stage I:
+ Configuration [] l_schemaNodes = a_config.getChildren("schema") ;
+ String l_schemaName = null ;
+ String l_schemaFile = null ;
+ SchemaImpl l_schema = null ;
+ for(int ii = 0; ii < l_schemaNodes.length; ii++) {
+ l_schemaName = l_schemaNodes[ii].getAttribute("name") ;
+ l_schemaFile = l_baseDir + File.separator +
+ l_schemaNodes[ii].getAttribute("filepath") ;
+ l_schema = parse(l_schemaFile) ;
+ m_complete.addSchema(l_schema) ;
+ m_schemaFileMap.put(l_schemaName, l_schema) ;
+ }
+
+ // Stage II:
+ Configuration [] l_normalizers =
+ a_config.getChild("normalization").getChildren("normalizer") ;
+ String l_rule = null ;
+ Normalizer l_normalizer = null ;
+ for(int ii = 0; ii < l_normalizers.length; ii++) {
+ l_rule = l_normalizers[ii].getAttribute("rule").toLowerCase() ;
+ l_normalizer = buildNormalizer(l_rule, l_normalizers[ii]) ;
+ m_normalizerMap.put(l_rule, l_normalizer) ;
+ }
+
+
+ // Stage III:
+ Configuration [] l_syntaxes =
+ a_config.getChild("syntax-checkers").getChildren("syntax-checker") ;
+ String l_oid = null ;
+ SyntaxChecker l_checker = null ;
+ for(int ii = 0; ii < l_syntaxes.length; ii++) {
+ l_oid = l_syntaxes[ii].getAttribute("oid") ;
+ l_checker = buildSyntaxChecker(l_oid, l_syntaxes[ii]) ;
+ m_syntaxCheckerMap.put(l_oid, l_checker) ;
+ }
+ m_complete.setNormalizers(m_normalizerMap) ;
+ m_complete.setSyntaxCheckers(m_syntaxCheckerMap) ;
+ Iterator l_list = m_schemaFileMap.values().iterator() ;
+ while(l_list.hasNext()) {
+ l_schema = (SchemaImpl) l_list.next() ;
+ l_schema.setNormalizers(m_normalizerMap) ;
+ l_schema.setSyntaxCheckers(m_syntaxCheckerMap) ;
+ }
+
+ // Stage IV:
+ // This stage must be last since we need the normalizers to be able to
+ // process the keys for distinguished names used to refer to a SAA
+ //
+
+ Configuration [] l_saaNodes = a_config.getChildren("SAA") ;
+ String l_saaDN = null ;
+ for(int ii = 0; ii < l_saaNodes.length; ii++) {
+ try {
+ l_saaDN =
+ m_complete.normalize(Schema.DN_ATTR,
+ l_saaNodes[ii].getAttribute("dn")) ;
+ } catch(NamingException e) {
+ throw new ConfigurationException("Failed to normalize SAA DN",
+ e) ;
+ }
+
+ l_schema = buildSAASchema(l_saaNodes[ii]) ;
+ l_schema.setNormalizers(m_normalizerMap) ;
+ l_schema.setSyntaxCheckers(m_syntaxCheckerMap) ;
+ m_suffixSchemaMap.put(l_saaDN, l_schema) ;
+ }
+ }
+
+
+ SyntaxChecker buildSyntaxChecker(String a_oid, Configuration a_syntaxNode)
+ throws ConfigurationException
+ {
+ Configuration [] l_regexes = a_syntaxNode.getChildren("regex") ;
+ String [] l_exprArray = new String [l_regexes.length] ;
+ for(int ii = 0; ii < l_regexes.length; ii++) {
+ l_exprArray[ii] = l_regexes[ii].getAttribute("value") ;
+ }
+
+ return new RegexSyntaxChecker(a_oid, l_exprArray) ;
+ }
+
+
+ Normalizer buildNormalizer(final String a_rule, Configuration a_node)
+ throws ConfigurationException
+ {
+ // Regex Form:
+ if(null == a_node.getAttribute("op", null)) {
+ Configuration [] l_regexes =
+ a_node.getChildren("regex") ;
+ String [] l_exprArray = new String [l_regexes.length] ;
+
+ for(int jj = 0; jj < l_regexes.length; jj++) {
+ l_exprArray[jj] = l_regexes[jj].getAttribute("value") ;
+ }
+
+ return new RegexNormalizer(a_rule, l_exprArray) ;
+ } else { // Non-Regex Form:
+ String l_op = a_node.getAttribute("op", null) ;
+ if(l_op.equals("deepTrimToLower")) {
+ return new AbstractNormalizer(a_rule, "deepTrimToLower") {
+ public String normalize(String a_value) {
+ return StringTools.deepTrimToLower(a_value) ;
+ }
+ } ;
+ } else if(l_op.equals("deepTrim")) {
+ return new AbstractNormalizer(a_rule, "deepTrim") {
+ public String normalize(String a_value) {
+ return StringTools.deepTrim(a_value) ;
+ }
+ } ;
+ } else if(l_op.equals("dnNormalize")) {
+ return new AbstractNormalizer(a_rule, "dnNormalize") {
+ public String normalize(String a_value)
+ throws NamingException
+ {
+ return m_complete.getNormalizingParser().
+ parse(a_value).toString() ;
+ }
+ } ;
+ } else if(l_op.equals("trim")) {
+ return new AbstractNormalizer(a_rule, "trim") {
+ public String normalize(String a_value) {
+ return a_value.trim() ;
+ }
+ } ;
+ } else {
+ return new AbstractNormalizer(a_rule, "asis") {
+ public String normalize(String a_value) {
+ return a_value ;
+ }
+ } ;
+ }
+ }
+ }
+
+
+ public abstract class AbstractNormalizer
+ implements Normalizer
+ {
+ final String m_rule ;
+ final String m_func ;
+
+ AbstractNormalizer(String a_rule, String a_func) {
+ m_rule = a_rule ;
+ m_func = a_func ;
+ }
+
+ public String getEqualityMatch() { return m_rule ; }
+ public String toString() {
+ StringBuffer l_buf = new StringBuffer() ;
+ l_buf.append("Normalizer(Rule: ").append(m_rule) ;
+ l_buf.append(", Function: ").append(m_func).append(')') ;
+ return l_buf.toString() ;
+ }
+ }
+
+
+ SchemaImpl buildSAASchema(Configuration a_saaNode)
+ throws ConfigurationException
+ {
+ SchemaImpl l_saaSchema = new SchemaImpl() ;
+ l_saaSchema.enableLogging(getLogger()) ;
+ SchemaImpl l_fileSchema = null ;
+ Configuration [] l_refs = a_saaNode.getChildren("schema-ref") ;
+ for(int ii = 0; ii < l_refs.length; ii++) {
+ l_fileSchema = (SchemaImpl)
+ m_schemaFileMap.get(l_refs[ii].getAttribute("schema")) ;
+
+ Iterator l_attributes = l_fileSchema.listAttributeSpecs() ;
+ while(l_attributes.hasNext()) {
+ l_saaSchema.addAttributeSpec(
+ (AttributeSpec) l_attributes.next()) ;
+ }
+
+ Iterator l_objectclasses = l_fileSchema.listObjectClassSpecs() ;
+ while(l_objectclasses.hasNext()) {
+ l_saaSchema.addObjectClassSpec(
+ (ObjectClassSpec) l_objectclasses.next()) ;
+ }
+ }
+
+ return l_saaSchema ;
+ }
+
+
+ SchemaImpl parse(String a_filename)
+ throws ConfigurationException
+ {
+ SchemaImpl l_schema = null ;
+
+ try {
+ antlrSchemaSyntaxLexer lexer =
+ new antlrSchemaSyntaxLexer( new FileInputStream(a_filename ) ) ;
+ l_schema = new SchemaImpl() ;
+ l_schema.enableLogging(getLogger()) ;
+ antlrSchemaParser l_parser =
+ new antlrSchemaParser(lexer) ;
+ l_parser.schemafile(l_schema) ;
+ } catch(FileNotFoundException e) {
+ throw new ConfigurationException(a_filename + " not found.", e) ;
+ } catch(TokenStreamException e) {
+ throw new ConfigurationException("parser failed on "
+ + a_filename, e) ;
+ } catch(RecognitionException e) {
+ throw new ConfigurationException("parser failed on "
+ + a_filename, e) ;
+ }
+
+ return l_schema ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/schema/SyntaxChecker.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/schema/SyntaxChecker.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,18 @@
+/*
+ * $Id: SyntaxChecker.java,v 1.3 2003/03/13 18:28:09 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.schema ;
+
+
+public interface SyntaxChecker
+{
+
+ String getSyntaxOid() ;
+ boolean isValidSyntax(String a_string) ;
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/security/LdapPrincipal.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/security/LdapPrincipal.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,71 @@
+/*
+ * $Id: LdapPrincipal.java,v 1.1 2003/03/26 02:07:19 jmachols Exp $
+ * $Prologue$
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.security ;
+
+
+import java.util.Locale ;
+import javax.naming.Name ;
+import java.security.Principal ;
+import org.apache.ldap.common.name.LdapName ;
+
+
+/**
+ * Principal implementation with some extra methods to access the Principal's
+ * locale and get the principal's name as a javax.naming.Name.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: jmachols $
+ * @version $Revision: 1.1 $
+ */
+public class LdapPrincipal
+ implements Principal
+{
+ public final static String ANONYMOUS = "" ;
+ final Name m_name ;
+ final Locale m_locale ;
+
+
+ public LdapPrincipal()
+ {
+ this(new LdapName(), Locale.getDefault()) ;
+ }
+
+
+ public LdapPrincipal(Name a_name)
+ {
+ this(a_name, Locale.getDefault()) ;
+ }
+
+
+ public LdapPrincipal(Name a_name, Locale a_locale)
+ {
+ m_name = a_name ;
+ m_locale = a_locale ;
+ }
+
+
+ public String getName()
+ {
+ return m_name.toString() ;
+ }
+
+
+ public Name getDn()
+ {
+ return m_name ;
+ }
+
+
+ public Locale getLocale()
+ {
+ return m_locale ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/security/auth/AuthenticationException.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/security/auth/AuthenticationException.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,41 @@
+/*
+ * $Id: AuthenticationException.java,v 1.3 2003/03/13 18:28:11 akarasulu Exp $
+ * $Prologue$
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.security.auth;
+
+import org.apache.avalon.framework.CascadingException;
+
+/** This exception is thrown when failed to authenticate occurred */
+public class AuthenticationException extends CascadingException
+{
+ /** Constructs an Exception without a message. */
+ public AuthenticationException(Throwable a_throwable)
+ {
+ super(a_throwable.getMessage()) ;
+ }
+
+ /**
+ * Constructs an Exception with a detailed message.
+ * @param Message The message associated with the exception.
+ */
+ public AuthenticationException(String message, Throwable a_throwable)
+ {
+ super(message, a_throwable) ;
+ }
+
+ /**
+ * Constructs an Exception with a detailed message.
+ * @param Message The message associated with the exception.
+ */
+ public AuthenticationException(String message)
+ {
+ super(message) ;
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/security/auth/AuthenticationManager.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/security/auth/AuthenticationManager.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,38 @@
+/*
+ * $Id: AuthenticationManager.java,v 1.5 2003/08/22 21:15:56 akarasulu Exp $
+ * $Prologue$
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.security.auth ;
+
+
+import org.apache.avalon.framework.component.Component ;
+import java.security.Principal ;
+import javax.naming.NamingException ;
+import org.apache.avalon.framework.CascadingException;
+import org.apache.eve.backend.BackendException;
+import javax.naming.Name ;
+import org.apache.eve.security.LdapPrincipal ;
+
+
+/**
+ * A service interface for centralized authentication management. At this point
+ * this is a very simple stub whose interface will definately change to take
+ * advantage of JAAS LoginModules and stack PAM via Java extended security
+ * serivices. For now we enable simple clear text authentication for simple
+ * binds via a loginSimple() interface.
+ */
+public interface AuthenticationManager
+ extends Component
+{
+ public static final String ROLE = AuthenticationManager.class.getName() ;
+
+ LdapPrincipal loginSimple( Name a_dn, String a_clearTextPassword )
+ throws AuthenticationException, BackendException, NamingException ;
+}
+
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/security/auth/AuthenticationModule.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/security/auth/AuthenticationModule.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,180 @@
+/*
+ * $Id: AuthenticationModule.java,v 1.8 2003/08/22 21:15:56 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.security.auth ;
+
+
+import java.util.Iterator ;
+import java.security.Principal ;
+
+import javax.naming.Name ;
+import javax.naming.NamingException ;
+import javax.naming.NameNotFoundException ;
+
+import org.apache.eve.AbstractModule ;
+import org.apache.eve.backend.LdapEntry ;
+import org.apache.eve.backend.AtomicBackend ;
+import org.apache.eve.security.LdapPrincipal ;
+import org.apache.eve.backend.UnifiedBackend ;
+import org.apache.eve.backend.BackendException ;
+
+import org.apache.avalon.framework.CascadingException ;
+import org.apache.avalon.framework.service.ServiceManager ;
+import org.apache.avalon.framework.service.ServiceException ;
+import org.apache.avalon.framework.configuration.Configuration ;
+import org.apache.avalon.framework.configuration.ConfigurationException ;
+
+
+/**
+ * Authenticates users against the backend.
+ *
+ * @phoenix:block
+ * @phoenix:service name="org.apache.eve.security.auth.AuthenticationManager"
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Revision: 1.8 $
+ */
+public class AuthenticationModule
+ extends AbstractModule
+ implements AuthenticationManager
+{
+ public static final String SIMPLE_PASSWORD_ATTR = "userPassword" ;
+ /**
+ * @todo Make sure we add a configuration parameter to enable and disable
+ * annonymous binds.
+ */
+ private boolean allowsAnnonymousBind = true ;
+ UnifiedBackend m_nexus = null ;
+
+
+ public LdapPrincipal loginSimple( Name a_dn, String a_password )
+ throws AuthenticationException, BackendException, NamingException
+ {
+ LdapPrincipal l_principal = null ;
+
+ if(a_dn.toString().trim().equals("")) {
+ if(allowsAnnonymousBind) {
+ getLogger().info("Annonymous bind granted!") ;
+ return new LdapPrincipal () ;
+ } else {
+ getLogger().info("Annoymous bind refused!") ;
+ throw new AuthenticationException("Annonymous binds disabled") ;
+ }
+ }
+
+ //
+ // First let's check if the user is a backend admin user before pulling
+ // records.
+ //
+
+ if( m_nexus.isAdminUser( a_dn ) ) {
+ if(getLogger().isDebugEnabled()) {
+ getLogger().debug(a_dn + " is an admin user.") ;
+ }
+
+ String l_password =
+ m_nexus.getBackend( a_dn ).getAdminUserPassword() ;
+
+ if(l_password.equals(a_password)) {
+ l_principal = new LdapPrincipal (a_dn) ;
+ return l_principal ;
+ } else {
+ String l_msg = "Authentication Failed: recognized admin "
+ + a_dn + " had invalid credentials!" ;
+ getLogger().info(l_msg) ;
+ throw new AuthenticationException(l_msg) ;
+ }
+ } else if(getLogger().isDebugEnabled()) {
+ getLogger().debug(a_dn + " not recognized as an admin user.") ;
+ }
+
+ try {
+ LdapEntry l_entry = m_nexus.read(a_dn) ;
+
+ if(!l_entry.hasAttribute(SIMPLE_PASSWORD_ATTR)) {
+ String l_msg = "Cannot authenticate " + a_dn +
+ " without a " + SIMPLE_PASSWORD_ATTR + " attribute!" ;
+ getLogger().info(l_msg) ;
+ throw new AuthenticationException(l_msg) ;
+ }
+
+ String l_password = (String)
+ l_entry.getSingleValue(SIMPLE_PASSWORD_ATTR) ;
+
+ if(null == l_password) {
+ String l_msg = "User " + a_dn + " cannot be authenticated with"
+ + " with a null password!" ;
+ getLogger().info(l_msg) ;
+ throw new AuthenticationException(l_msg) ;
+ }
+
+ if(l_password.equals(a_password)) {
+ l_principal = new LdapPrincipal (a_dn) ;
+ } else {
+ String l_msg = "User " + a_dn + " had invalid credentials!" ;
+ getLogger().info(l_msg) ;
+
+ if(getLogger().isDebugEnabled()) {
+ getLogger().debug(a_dn + " user provided password = " +
+ a_password + " entry password = " + l_password) ;
+ }
+
+ throw new AuthenticationException(l_msg) ;
+ }
+ } catch(BackendException e) {
+ getLogger().error("Authentication failure due to backend: ", e) ;
+ throw e ;
+ } catch(NameNotFoundException e) {
+ getLogger().error("Authentication failed: " + a_dn
+ + " does not exist!") ;
+ throw e ;
+ }
+
+ return l_principal ;
+ }
+
+
+ public void configure(Configuration a_config)
+ throws ConfigurationException
+ {
+ // Does nothing - no configuration need right now.
+ }
+
+
+ public String getImplementationRole()
+ {
+ return ROLE ;
+ }
+
+
+ public String getImplementationName()
+ {
+ return "Simple Authentication Module" ;
+ }
+
+
+ public String getImplementationClassName()
+ {
+ return this.getClass().getName() ;
+ }
+
+
+ /**
+ * Need handle on the nexus module - the unified backend.
+ *
+ * @phoenix:dependency name="org.apache.eve.backend.UnifiedBackend"
+ */
+ public void service(ServiceManager a_manager)
+ throws ServiceException
+ {
+ m_nexus = (UnifiedBackend) a_manager.lookup(UnifiedBackend.ROLE) ;
+ }
+}
+
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/seda/AbstractStage.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/seda/AbstractStage.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,261 @@
+/*
+ * $Id: AbstractStage.java,v 1.4 2003/08/01 05:41:27 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.seda ;
+
+
+import java.util.ArrayList ;
+import java.util.LinkedList ;
+import java.util.EventObject ;
+
+import org.apache.excalibur.thread.ThreadPool ;
+import org.apache.avalon.framework.service.ServiceManager ;
+import org.apache.avalon.framework.service.ServiceException ;
+import org.apache.avalon.framework.CascadingRuntimeException ;
+import org.apache.avalon.framework.configuration.Configuration ;
+import org.apache.avalon.cornerstone.services.threads.ThreadManager ;
+import org.apache.avalon.framework.configuration.ConfigurationException ;
+
+import org.apache.eve.AbstractModule ;
+import org.apache.eve.event.EventHandler ;
+
+
+/**
+ * We don't follow the SEDA API and over simply most of it. A stage to us is
+ * the queue as well and hence does not expose itself as a Source no dequeue
+ * mechanism exists. We will however use queue predicates so that we can
+ * control aspects of the enqueue process. This will be very interesting to
+ * us while filtering certain requests. The ACI mechanism can be based on this
+ * there is much potential.
+ *
+ * Our system is very specific and simple. We do not deal with bulk events
+ * getting enqueued at any one time and do not need the sophistication within
+ * some of the enqueue overloads.
+ *
+ * This stage base class presumes the handler is created by the concrete stage
+ * at some point before the start() method is called.
+ */
+public abstract class AbstractStage
+ extends AbstractModule implements Stage, Runnable
+{
+ private static final long DRIVER_WAIT = 200 ;
+ private LinkedList m_queue = new LinkedList() ;
+ private String m_name = null ;
+ private String m_poolName = null ;
+ private boolean m_running = false ;
+ private ArrayList m_predicates = new ArrayList() ;
+ protected ThreadManager m_threadManager = null ;
+ protected EventHandler m_handler = null ;
+
+
+ ///////////////////////////
+ // Stage Implementations //
+ ///////////////////////////
+
+
+ public void addPredicate(EnqueuePredicate a_predicate)
+ {
+ m_predicates.add(a_predicate) ;
+ }
+
+
+ public void enqueue(final EventObject an_event)
+ throws CascadingRuntimeException
+ {
+ if(!hasStarted()) {
+ throw new CascadingRuntimeException(
+ "Cannot enqueue on a stage that has not been started", null) ;
+ }
+
+ boolean l_isAccepted = true ;
+ for(int ii = 0; ii < m_predicates.size() && l_isAccepted; ii++) {
+ EnqueuePredicate l_test = (EnqueuePredicate) m_predicates.get(ii) ;
+ l_isAccepted &= l_test.accept(an_event) ;
+ }
+
+ if(l_isAccepted) {
+ if(getLogger().isDebugEnabled()) {
+ getLogger().debug("Enqueue operation accepted. Performing "
+ + "synchronized push of event " + an_event + " on to stage "
+ + m_name + " queue.") ;
+ }
+ synchronized(m_queue) {
+ if(getLogger().isDebugEnabled()) {
+ getLogger().debug("Grabbed lock on queue for event " +
+ an_event + " push onto queue") ;
+ }
+ m_queue.addFirst(an_event) ;
+ m_queue.notifyAll() ;
+ }
+
+ getLogger().debug("Enqueue operation successfully completed") ;
+ } else {
+ if(getLogger().isInfoEnabled()) {
+ getLogger().info("Stage " + m_name
+ + " predicates dropped event " + an_event
+ + " on enqueue operation") ;
+ }
+ }
+ }
+
+
+ /////////////////////////////
+ // Runnable Implementation //
+ /////////////////////////////
+
+
+ public final void run()
+ {
+ if(getLogger().isDebugEnabled()) {
+ getLogger().debug("Stage " + m_name + " started handler thread") ;
+ }
+
+ while(hasStarted()) {
+ synchronized(m_queue) {
+ if(m_queue.isEmpty()) {
+ try {
+ m_queue.wait(DRIVER_WAIT) ;
+ } catch(InterruptedException e) {
+ try { stop() ; } catch (Exception e2) {/*NOT THROWN*/}
+ getLogger().error("Stage stopped due to driver thread "
+ + "failure: ", e) ;
+ }
+ } else {
+ final EventObject l_event =
+ (EventObject) m_queue.removeLast() ;
+
+ if(getLogger().isDebugEnabled()) {
+ getLogger().debug("Stage " + m_name + " popped event "
+ + l_event + " for processing") ;
+ }
+
+ final Runnable l_runnable = new Runnable()
+ {
+ public void run()
+ {
+ try {
+ m_handler.handleEvent(l_event) ;
+ } catch(Throwable t) {
+ getLogger().error("Stage " + m_name
+ + " failed on event " + l_event
+ + " in handler thread", t) ;
+ }
+ }
+ } ;
+
+ ThreadPool l_pool =
+ m_threadManager.getThreadPool(m_poolName) ;
+ l_pool.execute(l_runnable) ;
+ }
+ }
+ }
+ }
+
+
+ ////////////////////////
+ // Life-cycle Methods //
+ ////////////////////////
+
+
+ public void start()
+ throws Exception
+ {
+ super.start() ;
+ (new Thread(this)).start() ;
+ }
+
+
+ public void stop()
+ throws Exception
+ {
+ m_running = false ;
+
+ synchronized(this) {
+ // Wake up the driver thread if it is in a wait state.
+ this.notifyAll() ;
+ }
+
+ // Sleep waiting for our driver thread to terminate!
+ Thread.currentThread().sleep(DRIVER_WAIT) ;
+ super.stop() ;
+ }
+
+
+ public void service(ServiceManager a_manager)
+ throws ServiceException
+ {
+ super.service(a_manager) ;
+ m_threadManager = (ThreadManager)
+ a_manager.lookup(ThreadManager.ROLE) ;
+ }
+
+
+ /*
+ E X A M P L E C O N F I G
+ <toplevel-blockname-tag>
+ <stage name="protocol-stage" poolname="processors"
+ handler="org.apache.eve.protocol.ProtocolHandler">
+ <predicate
+ class="org.apache.eve.protocol.BindPredicate"/>
+ <predicate
+ class="org.apache.eve.protocol.LoadPredicate"/>
+ <predicate
+ class="org.apache.eve.protocol.PermissionsPredicate"/>
+ </stage>
+
+ <!-- Other block specific configurations can be handled anywhere -->
+ </toplevel-blockname-tag>
+ */
+
+ public void configure(Configuration a_config)
+ throws ConfigurationException
+ {
+ m_name =
+ a_config.getChild("stage").getAttribute("name") ;
+ m_poolName =
+ a_config.getChild("stage").getAttribute("poolname") ;
+
+ if(null == m_name || null == m_poolName) {
+ throw new ConfigurationException("name or poolname attributes must "
+ + "be supplied for a stage!") ;
+ }
+
+ String l_handlerFQN =
+ a_config.getChild("stage").getAttribute("handler", null) ;
+
+ // If handler is null then we presume that the concrete subclass
+ // will instantiate and initialize the handler by itself.
+ if(l_handlerFQN != null) {
+ try {
+ m_handler =
+ (EventHandler) Class.forName(l_handlerFQN).newInstance() ;
+ } catch(Exception e) {
+ throw new ConfigurationException("Could not instantiate the "
+ + "event handler for stage " + m_name
+ + " using the fully qualified event handler class name of "
+ + l_handlerFQN) ;
+ }
+ }
+
+ Configuration [] l_predicates = a_config.getChildren("predicate") ;
+ for(int ii = 0; ii < l_predicates.length; ii++) {
+ String l_className = l_predicates[ii].getAttribute("class") ;
+
+ try {
+ m_predicates.add((EnqueuePredicate)
+ Class.forName(l_className).newInstance()) ;
+ } catch(Exception e) {
+ throw new ConfigurationException("Could not instantiate an "
+ + "enqueue predicate for stage " + m_name
+ + " using the fully qualified class name of "
+ + l_handlerFQN) ;
+ }
+ }
+ }
+}
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/seda/EnqueuePredicate.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/seda/EnqueuePredicate.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,22 @@
+/*
+ * $Id: EnqueuePredicate.java,v 1.3 2003/03/13 18:28:14 akarasulu Exp $
+ * $Prologue$
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.seda ;
+
+import java.util.EventObject ;
+import org.apache.avalon.framework.CascadingRuntimeException ;
+
+
+public interface EnqueuePredicate
+{
+ public boolean accept(EventObject an_event)
+ throws CascadingRuntimeException ;
+}
+
Added: incubator/directory/eve/branches/start/src/java/org/apache/eve/seda/Stage.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/java/org/apache/eve/seda/Stage.java Thu Jun 24 00:06:35 2004
@@ -0,0 +1,23 @@
+/*
+ * $Id: Stage.java,v 1.3 2003/03/13 18:28:15 akarasulu Exp $
+ * $Prologue$
+ *
+ * -- (c) LDAPd Group --
+ * -- Please refer to the LICENSE.txt file in the root directory of --
+ * -- any LDAPd project for copyright and distribution information. --
+ *
+ */
+
+package org.apache.eve.seda ;
+
+
+import java.util.EventObject ;
+import org.apache.avalon.framework.CascadingRuntimeException ;
+
+
+public interface Stage
+{
+ void enqueue(EventObject an_event) throws CascadingRuntimeException ;
+ void addPredicate(EnqueuePredicate a_predicate) ;
+}
+
Added: incubator/directory/eve/branches/start/src/ldif/addAll.ldif
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/ldif/addAll.ldif Thu Jun 24 00:06:35 2004
@@ -0,0 +1,12 @@
+dn: dc=domain,dc=com
+objectclass: dcObject
+dc: domain
+
+
+dn: cn=testuser,dc=domain,dc=com
+objectclass: inetOrgPerson
+cn: testuser
+sn: nobody
+userPassword: dumass
+
+
Added: incubator/directory/eve/branches/start/src/ldif/addRoot.ldif
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/ldif/addRoot.ldif Thu Jun 24 00:06:35 2004
@@ -0,0 +1,4 @@
+dn: dc=domain,dc=com
+objectclass: dcObject
+dc: domain
+
Added: incubator/directory/eve/branches/start/src/ldif/addTestUser.ldif
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/ldif/addTestUser.ldif Thu Jun 24 00:06:35 2004
@@ -0,0 +1,7 @@
+dn: cn=testuser,dc=domain,dc=com
+objectclass: inetOrgPerson
+cn: testuser
+sn: nobody
+userPassword: dumass
+
+
Added: incubator/directory/eve/branches/start/src/ldif/example.ldif
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/ldif/example.ldif Thu Jun 24 00:06:35 2004
@@ -0,0 +1,2786 @@
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# dc=domain,dc=com sample LDIF file
+#
+# Notes:
+# 160 total entries.
+# 1 (objectclass=domain) entry (dc=domain,dc=com).
+# 4 (objectclass=organizationalunit) entries.
+# 5 (objectclass=groupofuniquenames) entries.
+# 150 (objectclass=person) entries (all under ou=people,dc=domain,dc=com).
+#
+
+dn: ou=Groups,dc=domain,dc=com
+objectclass: top
+objectclass: organizationalunit
+ou: Groups
+
+dn: cn=Directory Administrators,ou=Groups,dc=domain,dc=com
+cn: Directory Administrators
+objectclass: top
+objectclass: groupofuniquenames
+ou: Groups
+uniquemember: uid=kvaughan,ou=People,dc=domain,dc=com
+uniquemember: uid=rdaugherty,ou=People,dc=domain,dc=com
+uniquemember: uid=hmiller,ou=People,dc=domain,dc=com
+
+dn: ou=Special Users,dc=domain,dc=com
+objectclass: top
+objectclass: organizationalUnit
+ou: Special Users
+description: Special Administrative Accounts
+
+# Start from here for netscape iPlanet (SUN One Directory Server)
+
+dn: ou=People,dc=domain,dc=com
+objectclass: top
+objectclass: organizationalunit
+ou: People
+
+dn: uid=scarter,ou=People,dc=domain,dc=com
+cn: Sam Carter
+sn: Carter
+givenname: Sam
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: scarter
+mail: scarter@domain.com
+telephonenumber: +1 408 555 4798
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 4612
+userpassword: sprain
+
+dn: uid=tmorris,ou=People,dc=domain,dc=com
+cn: Ted Morris
+sn: Morris
+givenname: Ted
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: tmorris
+mail: tmorris@domain.com
+telephonenumber: +1 408 555 9187
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 4117
+userpassword: irrefutable
+
+dn: uid=kvaughan,ou=People,dc=domain,dc=com
+cn: Kirsten Vaughan
+sn: Vaughan
+givenname: Kirsten
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: kvaughan
+mail: kvaughan@domain.com
+telephonenumber: +1 408 555 5625
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 2871
+userpassword: bribery
+
+dn: uid=abergin,ou=People,dc=domain,dc=com
+cn: Andy Bergin
+sn: Bergin
+givenname: Andy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Cupertino
+uid: abergin
+mail: abergin@domain.com
+telephonenumber: +1 408 555 8585
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 3472
+userpassword: inflict
+
+dn: uid=dmiller,ou=People,dc=domain,dc=com
+cn: David Miller
+sn: Miller
+givenname: David
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: dmiller
+mail: dmiller@domain.com
+telephonenumber: +1 408 555 9423
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 4135
+userpassword: gosling
+
+dn: uid=gfarmer,ou=People,dc=domain,dc=com
+cn: Gern Farmer
+sn: Farmer
+givenname: Gern
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: gfarmer
+mail: gfarmer@domain.com
+telephonenumber: +1 408 555 6201
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1269
+userpassword: ruling
+
+dn: uid=kwinters,ou=People,dc=domain,dc=com
+cn: Kelly Winters
+sn: Winters
+givenname: Kelly
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: kwinters
+mail: kwinters@domain.com
+telephonenumber: +1 408 555 9069
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 4178
+userpassword: forsook
+
+dn: uid=trigden,ou=People,dc=domain,dc=com
+cn: Torrey Rigden
+sn: Rigden
+givenname: Torrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: trigden
+mail: trigden@domain.com
+telephonenumber: +1 408 555 9280
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 3584
+userpassword: sensitive
+
+dn: uid=cschmith,ou=People,dc=domain,dc=com
+cn: Chris Schmith
+sn: Schmith
+givenname: Chris
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: cschmith
+mail: cschmith@domain.com
+telephonenumber: +1 408 555 8011
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0416
+userpassword: hypotenuse
+
+dn: uid=jwallace,ou=People,dc=domain,dc=com
+cn: Judy Wallace
+sn: Wallace
+givenname: Judy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: jwallace
+mail: jwallace@domain.com
+telephonenumber: +1 408 555 0319
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1033
+userpassword: linear
+
+dn: uid=jwalker,ou=People,dc=domain,dc=com
+cn: John Walker
+sn: Walker
+givenname: John
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Cupertino
+uid: jwalker
+mail: jwalker@domain.com
+telephonenumber: +1 408 555 1476
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 3915
+userpassword: dogleg
+
+dn: uid=tclow,ou=People,dc=domain,dc=com
+cn: Torrey Clow
+sn: Clow
+givenname: Torrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: tclow
+mail: tclow@domain.com
+telephonenumber: +1 408 555 8825
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 4376
+userpassword: cardreader
+
+dn: uid=rdaugherty,ou=People,dc=domain,dc=com
+cn: Robert Daugherty
+sn: Daugherty
+givenname: Robert
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: rdaugherty
+mail: rdaugherty@domain.com
+telephonenumber: +1 408 555 1296
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 0194
+userpassword: apples
+
+dn: uid=jreuter,ou=People,dc=domain,dc=com
+cn: Jayne Reuter
+sn: Reuter
+givenname: Jayne
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Cupertino
+uid: jreuter
+mail: jreuter@domain.com
+telephonenumber: +1 408 555 1122
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 2942
+userpassword: destroy
+
+dn: uid=tmason,ou=People,dc=domain,dc=com
+cn: Torrey Mason
+sn: Mason
+givenname: Torrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: tmason
+mail: tmason@domain.com
+telephonenumber: +1 408 555 1596
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 1124
+userpassword: squatted
+
+dn: uid=bhall,ou=People,dc=domain,dc=com
+cn: Benjamin Hall
+sn: Hall
+givenname: Benjamin
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: bhall
+mail: bhall@domain.com
+telephonenumber: +1 408 555 6067
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 2511
+userpassword: oranges
+
+dn: uid=btalbot,ou=People,dc=domain,dc=com
+cn: Brad Talbot
+sn: Talbot
+givenname: Brad
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: btalbot
+mail: btalbot@domain.com
+telephonenumber: +1 408 555 4992
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 3532
+userpassword: trident
+
+dn: uid=mward,ou=People,dc=domain,dc=com
+cn: Marcus Ward
+sn: Ward
+givenname: Marcus
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: mward
+mail: mward@domain.com
+telephonenumber: +1 408 555 5688
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 1707
+userpassword: normal
+
+dn: uid=bjablons,ou=People,dc=domain,dc=com
+cn: Barbara Jablonski
+sn: Jablonski
+givenname: Barbara
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: bjablons
+mail: bjablons@domain.com
+telephonenumber: +1 408 555 8815
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0906
+userpassword: strawberry
+
+dn: uid=jmcFarla,ou=People,dc=domain,dc=com
+cn: Judy McFarland
+sn: McFarland
+givenname: Judy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: jmcFarla
+mail: jmcFarla@domain.com
+telephonenumber: +1 408 555 2567
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 2359
+userpassword: walnut
+
+dn: uid=llabonte,ou=People,dc=domain,dc=com
+cn: Lee Labonte
+sn: Labonte
+givenname: Lee
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: llabonte
+mail: llabonte@domain.com
+telephonenumber: +1 408 555 0957
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 2854
+userpassword: sourdough
+
+dn: uid=jcampaig,ou=People,dc=domain,dc=com
+cn: Jody Campaigne
+sn: Campaigne
+givenname: Jody
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: jcampaig
+mail: jcampaig@domain.com
+telephonenumber: +1 408 555 1660
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 4385
+userpassword: grapevine
+
+dn: uid=bhal2,ou=People,dc=domain,dc=com
+cn: Barbara Hall
+sn: Hall
+givenname: Barbara
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: bhal2
+mail: bhal2@domain.com
+telephonenumber: +1 408 555 4491
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 2758
+userpassword: truths
+
+dn: uid=alutz,ou=People,dc=domain,dc=com
+cn: Alexander Lutz
+sn: Lutz
+givenname: Alexander
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: alutz
+mail: alutz@domain.com
+telephonenumber: +1 408 555 6505
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 1327
+userpassword: northward
+
+dn: uid=btalbo2,ou=People,dc=domain,dc=com
+cn: Bjorn Talbot
+sn: Talbot
+givenname: Bjorn
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: btalbo2
+mail: btalbo2@domain.com
+telephonenumber: +1 408 555 4234
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 1205
+userpassword: corduroy
+
+dn: uid=achassin,ou=People,dc=domain,dc=com
+cn: Ashley Chassin
+sn: Chassin
+givenname: Ashley
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Santa Clara
+uid: achassin
+mail: achassin@domain.com
+telephonenumber: +1 408 555 9972
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 0466
+userpassword: duopolist
+
+dn: uid=hmiller,ou=People,dc=domain,dc=com
+cn: Harry Miller
+sn: Miller
+givenname: Harry
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: hmiller
+mail: hmiller@domain.com
+telephonenumber: +1 408 555 9804
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 4304
+userpassword: hillock
+
+dn: uid=jcampai2,ou=People,dc=domain,dc=com
+cn: Jeffrey Campaigne
+sn: Campaigne
+givenname: Jeffrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: jcampai2
+mail: jcampai2@domain.com
+telephonenumber: +1 408 555 7393
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 1377
+userpassword: nominee
+
+dn: uid=lulrich,ou=People,dc=domain,dc=com
+cn: Lee Ulrich
+sn: Ulrich
+givenname: Lee
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Sunnyvale
+uid: lulrich
+mail: lulrich@domain.com
+telephonenumber: +1 408 555 8652
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 0985
+userpassword: attribution
+
+dn: uid=mlangdon,ou=People,dc=domain,dc=com
+cn: Marcus Langdon
+sn: Langdon
+givenname: Marcus
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: mlangdon
+mail: mlangdon@domain.com
+telephonenumber: +1 408 555 6249
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 4471
+userpassword: threat
+
+dn: uid=striplet,ou=People,dc=domain,dc=com
+cn: Stephen Triplett
+sn: Triplett
+givenname: Stephen
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: striplet
+mail: striplet@domain.com
+telephonenumber: +1 408 555 4519
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 3083
+userpassword: compactify
+
+dn: uid=gtriplet,ou=People,dc=domain,dc=com
+cn: Gern Triplett
+sn: Triplett
+givenname: Gern
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: gtriplet
+mail: gtriplet@domain.com
+telephonenumber: +1 408 555 2582
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 4023
+userpassword: placeable
+
+dn: uid=jfalena,ou=People,dc=domain,dc=com
+cn: John Falena
+sn: Falena
+givenname: John
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: jfalena
+mail: jfalena@domain.com
+telephonenumber: +1 408 555 8133
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 1917
+userpassword: nightly
+
+dn: uid=speterso,ou=People,dc=domain,dc=com
+cn: Sue Peterson
+sn: Peterson
+givenname: Sue
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: speterso
+mail: speterso@domain.com
+telephonenumber: +1 408 555 3613
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 3073
+userpassword: quinine
+
+dn: uid=ejohnson,ou=People,dc=domain,dc=com
+cn: Emanuel Johnson
+sn: Johnson
+givenname: Emanuel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: ejohnson
+mail: ejohnson@domain.com
+telephonenumber: +1 408 555 3287
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 3737
+userpassword: marketwise
+
+dn: uid=prigden,ou=People,dc=domain,dc=com
+cn: Peter Rigden
+sn: Rigden
+givenname: Peter
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: prigden
+mail: prigden@domain.com
+telephonenumber: +1 408 555 5099
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1271
+userpassword: epiphyseal
+
+dn: uid=bwalker,ou=People,dc=domain,dc=com
+cn: Brad Walker
+sn: Walker
+givenname: Brad
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: bwalker
+mail: bwalker@domain.com
+telephonenumber: +1 408 555 5476
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 3529
+userpassword: interruptible
+
+dn: uid=kjensen,ou=People,dc=domain,dc=com
+cn: Kurt Jensen
+sn: Jensen
+givenname: Kurt
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: kjensen
+mail: kjensen@domain.com
+telephonenumber: +1 408 555 6127
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 1944
+userpassword: regulatory
+
+dn: uid=mlott,ou=People,dc=domain,dc=com
+cn: Mike Lott
+sn: Lott
+givenname: Mike
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: mlott
+mail: mlott@domain.com
+telephonenumber: +1 408 555 2234
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 0498
+userpassword: cognac
+
+dn: uid=cwallace,ou=People,dc=domain,dc=com
+cn: Cecil Wallace
+sn: Wallace
+givenname: Cecil
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: cwallace
+mail: cwallace@domain.com
+telephonenumber: +1 408 555 6438
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 0349
+userpassword: quintus
+
+dn: uid=tpierce,ou=People,dc=domain,dc=com
+cn: Tobias Pierce
+sn: Pierce
+givenname: Tobias
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: tpierce
+mail: tpierce@domain.com
+telephonenumber: +1 408 555 1531
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 1383
+userpassword: rascal
+
+dn: uid=rbannist,ou=People,dc=domain,dc=com
+cn: Richard Bannister
+sn: Bannister
+givenname: Richard
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: rbannist
+mail: rbannist@domain.com
+telephonenumber: +1 408 555 1833
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 0983
+userpassword: demonstrate
+
+dn: uid=bplante,ou=People,dc=domain,dc=com
+cn: Brian Plante
+sn: Plante
+givenname: Brian
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: bplante
+mail: bplante@domain.com
+telephonenumber: +1 408 555 3550
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 4654
+userpassword: tangerine
+
+dn: uid=rmills,ou=People,dc=domain,dc=com
+cn: Randy Mills
+sn: Mills
+givenname: Randy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: rmills
+mail: rmills@domain.com
+telephonenumber: +1 408 555 2072
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 3823
+userpassword: condescend
+
+dn: uid=bschneid,ou=People,dc=domain,dc=com
+cn: Benjamin Schneider
+sn: Schneider
+givenname: Benjamin
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: bschneid
+mail: bschneid@domain.com
+telephonenumber: +1 408 555 1012
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 4471
+userpassword: biblical
+
+dn: uid=skellehe,ou=People,dc=domain,dc=com
+cn: Sue Kelleher
+sn: Kelleher
+givenname: Sue
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Santa Clara
+uid: skellehe
+mail: skellehe@domain.com
+telephonenumber: +1 408 555 3480
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 1608
+userpassword: sweltering
+
+dn: uid=brentz,ou=People,dc=domain,dc=com
+cn: Bertram Rentz
+sn: Rentz
+givenname: Bertram
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Sunnyvale
+uid: brentz
+mail: brentz@domain.com
+telephonenumber: +1 408 555 5526
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 0617
+userpassword: diachronic
+
+dn: uid=dsmith,ou=People,dc=domain,dc=com
+cn: Daniel Smith
+sn: Smith
+givenname: Daniel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: dsmith
+mail: dsmith@domain.com
+telephonenumber: +1 408 555 9519
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 0368
+userpassword: quantitative
+
+dn: uid=scarte2,ou=People,dc=domain,dc=com
+cn: Stephen Carter
+sn: Carter
+givenname: Stephen
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: scarte2
+mail: scarte2@domain.com
+telephonenumber: +1 408 555 6022
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 2013
+userpassword: scooter
+
+dn: uid=dthorud,ou=People,dc=domain,dc=com
+cn: David Thorud
+sn: Thorud
+givenname: David
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: dthorud
+mail: dthorud@domain.com
+telephonenumber: +1 408 555 6185
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 1128
+userpassword: fulcrum
+
+dn: uid=ekohler,ou=People,dc=domain,dc=com
+cn: Elba Kohler
+sn: Kohler
+givenname: Elba
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: ekohler
+mail: ekohler@domain.com
+telephonenumber: +1 408 555 1926
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 2721
+userpassword: guildhall
+
+dn: uid=lcampbel,ou=People,dc=domain,dc=com
+cn: Laurel Campbell
+sn: Campbell
+givenname: Laurel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: lcampbel
+mail: lcampbel@domain.com
+telephonenumber: +1 408 555 2537
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 2073
+userpassword: impress
+
+dn: uid=tlabonte,ou=People,dc=domain,dc=com
+cn: Tim Labonte
+sn: Labonte
+givenname: Tim
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: tlabonte
+mail: tlabonte@domain.com
+telephonenumber: +1 408 555 0058
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 1426
+userpassword: express
+
+dn: uid=slee,ou=People,dc=domain,dc=com
+cn: Scott Lee
+sn: Lee
+givenname: Scott
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: slee
+mail: slee@domain.com
+telephonenumber: +1 408 555 2335
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 1806
+userpassword: revertive
+
+dn: uid=bfree,ou=People,dc=domain,dc=com
+cn: Bjorn Free
+sn: Free
+givenname: Bjorn
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: bfree
+mail: bfree@domain.com
+telephonenumber: +1 408 555 8588
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 3307
+userpassword: etiquette
+
+dn: uid=tschneid,ou=People,dc=domain,dc=com
+cn: Torrey Schneider
+sn: Schneider
+givenname: Torrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: tschneid
+mail: tschneid@domain.com
+telephonenumber: +1 408 555 7086
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 2292
+userpassword: chaperone
+
+dn: uid=prose,ou=People,dc=domain,dc=com
+cn: Paula Rose
+sn: Rose
+givenname: Paula
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: prose
+mail: prose@domain.com
+telephonenumber: +1 408 555 9998
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 0542
+userpassword: regatta
+
+dn: uid=jhunter,ou=People,dc=domain,dc=com
+cn: Janet Hunter
+sn: Hunter
+givenname: Janet
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: jhunter
+mail: jhunter@domain.com
+telephonenumber: +1 408 555 7665
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 4856
+userpassword: nanometer
+
+dn: uid=ashelton,ou=People,dc=domain,dc=com
+cn: Alexander Shelton
+sn: Shelton
+givenname: Alexander
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: ashelton
+mail: ashelton@domain.com
+telephonenumber: +1 408 555 1081
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 1987
+userpassword: appointe
+
+dn: uid=mmcinnis,ou=People,dc=domain,dc=com
+cn: Marcus Mcinnis
+sn: Mcinnis
+givenname: Marcus
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: mmcinnis
+mail: mmcinnis@domain.com
+telephonenumber: +1 408 555 9655
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 4818
+userpassword: calcify
+
+dn: uid=falbers,ou=People,dc=domain,dc=com
+cn: Frank Albers
+sn: Albers
+givenname: Frank
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: falbers
+mail: falbers@domain.com
+telephonenumber: +1 408 555 3094
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 1439
+userpassword: degradation
+
+dn: uid=mschneid,ou=People,dc=domain,dc=com
+cn: Martin Schneider
+sn: Schneider
+givenname: Martin
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: mschneid
+mail: mschneid@domain.com
+telephonenumber: +1 408 555 5017
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 3153
+userpassword: motorcycle
+
+dn: uid=pcruse,ou=People,dc=domain,dc=com
+cn: Patricia Cruse
+sn: Cruse
+givenname: Patricia
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: pcruse
+mail: pcruse@domain.com
+telephonenumber: +1 408 555 8641
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 3967
+userpassword: pauper
+
+dn: uid=tkelly,ou=People,dc=domain,dc=com
+cn: Timothy Kelly
+sn: Kelly
+givenname: Timothy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Santa Clara
+uid: tkelly
+mail: tkelly@domain.com
+telephonenumber: +1 408 555 4295
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 3107
+userpassword: risible
+
+dn: uid=ahel,ou=People,dc=domain,dc=com
+cn: Andrew Hel
+sn: Hel
+givenname: Andrew
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: ahel
+mail: ahel@domain.com
+telephonenumber: +1 408 555 2666
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 0572
+userpassword: sarsaparilla
+
+dn: uid=jburrell,ou=People,dc=domain,dc=com
+cn: James Burrell
+sn: Burrell
+givenname: James
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: jburrell
+mail: jburrell@domain.com
+telephonenumber: +1 408 555 0751
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 4926
+userpassword: degrease
+
+dn: uid=smason,ou=People,dc=domain,dc=com
+cn: Sue Mason
+sn: Mason
+givenname: Sue
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: smason
+mail: smason@domain.com
+telephonenumber: +1 408 555 9780
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 4971
+userpassword: sensible
+
+dn: uid=ptyler,ou=People,dc=domain,dc=com
+cn: Pete Tyler
+sn: Tyler
+givenname: Pete
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: ptyler
+mail: ptyler@domain.com
+telephonenumber: +1 408 555 3335
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0327
+userpassword: vinegar
+
+dn: uid=calexand,ou=People,dc=domain,dc=com
+cn: Chris Alexander
+sn: Alexander
+givenname: Chris
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Sunnyvale
+uid: calexand
+mail: calexand@domain.com
+telephonenumber: +1 408 555 9438
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 2884
+userpassword: dauphin
+
+dn: uid=jcruse,ou=People,dc=domain,dc=com
+cn: Jim Cruse
+sn: Cruse
+givenname: Jim
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Santa Clara
+uid: jcruse
+mail: jcruse@domain.com
+telephonenumber: +1 408 555 9482
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 0083
+userpassword: bridgework
+
+dn: uid=kcarter,ou=People,dc=domain,dc=com
+cn: Karen Carter
+sn: Carter
+givenname: Karen
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: kcarter
+mail: kcarter@domain.com
+telephonenumber: +1 408 555 4675
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 2320
+userpassword: radiosonde
+
+dn: uid=rfish,ou=People,dc=domain,dc=com
+cn: Randy Fish
+sn: Fish
+givenname: Randy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: rfish
+mail: rfish@domain.com
+telephonenumber: +1 408 555 9865
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 2317
+userpassword: mailbox
+
+dn: uid=phunt,ou=People,dc=domain,dc=com
+cn: Philip Hunt
+sn: Hunt
+givenname: Philip
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: phunt
+mail: phunt@domain.com
+telephonenumber: +1 408 555 1242
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 1183
+userpassword: wastewater
+
+dn: uid=rschneid,ou=People,dc=domain,dc=com
+cn: Rachel Schneider
+sn: Schneider
+givenname: Rachel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: rschneid
+mail: rschneid@domain.com
+telephonenumber: +1 408 555 9908
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 4183
+userpassword: decorous
+
+dn: uid=bjensen,ou=People,dc=domain,dc=com
+cn: Barbara Jensen
+cn: Babs Jensen
+sn: Jensen
+givenname: Barbara
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: bjensen
+mail: bjensen@domain.com
+telephonenumber: +1 408 555 1862
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 0209
+userpassword: hifalutin
+
+dn: uid=jlange,ou=People,dc=domain,dc=com
+cn: Jim Lange
+sn: Lange
+givenname: Jim
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: jlange
+mail: jlange@domain.com
+telephonenumber: +1 408 555 0488
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 3798
+userpassword: chastity
+
+dn: uid=rulrich,ou=People,dc=domain,dc=com
+cn: Randy Ulrich
+sn: Ulrich
+givenname: Randy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: rulrich
+mail: rulrich@domain.com
+telephonenumber: +1 408 555 5311
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 1282
+userpassword: twinkle
+
+dn: uid=rfrancis,ou=People,dc=domain,dc=com
+cn: Richard Francis
+sn: Francis
+givenname: Richard
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: rfrancis
+mail: rfrancis@domain.com
+telephonenumber: +1 408 555 8157
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 3482
+userpassword: hacienda
+
+dn: uid=mwhite,ou=People,dc=domain,dc=com
+cn: Morgan White
+sn: White
+givenname: Morgan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: mwhite
+mail: mwhite@domain.com
+telephonenumber: +1 408 555 9620
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 3088
+userpassword: staple
+
+dn: uid=gjensen,ou=People,dc=domain,dc=com
+cn: Gern Jensen
+sn: Jensen
+givenname: Gern
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: gjensen
+mail: gjensen@domain.com
+telephonenumber: +1 408 555 3299
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 4609
+userpassword: primitive
+
+dn: uid=awhite,ou=People,dc=domain,dc=com
+cn: Alan White
+sn: White
+givenname: Alan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Sunnyvale
+uid: awhite
+mail: awhite@domain.com
+telephonenumber: +1 408 555 3232
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 0142
+userpassword: placeholder
+
+dn: uid=bmaddox,ou=People,dc=domain,dc=com
+cn: Barbara Maddox
+sn: Maddox
+givenname: Barbara
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: bmaddox
+mail: bmaddox@domain.com
+telephonenumber: +1 408 555 7783
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 2207
+userpassword: feedback
+
+dn: uid=mtalbot,ou=People,dc=domain,dc=com
+cn: Martin Talbot
+sn: Talbot
+givenname: Martin
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: mtalbot
+mail: mtalbot@domain.com
+telephonenumber: +1 408 555 9228
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1415
+userpassword: currant
+
+dn: uid=jbrown,ou=People,dc=domain,dc=com
+cn: Judy Brown
+sn: Brown
+givenname: Judy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Santa Clara
+uid: jbrown
+mail: jbrown@domain.com
+telephonenumber: +1 408 555 6885
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 4224
+userpassword: militiamen
+
+dn: uid=jjensen,ou=People,dc=domain,dc=com
+cn: Jody Jensen
+sn: Jensen
+givenname: Jody
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: jjensen
+mail: jjensen@domain.com
+telephonenumber: +1 408 555 7587
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 4882
+userpassword: borderland
+
+dn: uid=mcarter,ou=People,dc=domain,dc=com
+cn: Mike Carter
+sn: Carter
+givenname: Mike
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: mcarter
+mail: mcarter@domain.com
+telephonenumber: +1 408 555 1846
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 3819
+userpassword: mainland
+
+dn: uid=dakers,ou=People,dc=domain,dc=com
+cn: David Akers
+sn: Akers
+givenname: David
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: dakers
+mail: dakers@domain.com
+telephonenumber: +1 408 555 4812
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 4944
+userpassword: integument
+
+dn: uid=sfarmer,ou=People,dc=domain,dc=com
+cn: Scott Farmer
+sn: Farmer
+givenname: Scott
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: sfarmer
+mail: sfarmer@domain.com
+telephonenumber: +1 408 555 4228
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 0019
+userpassword: triumphal
+
+dn: uid=dward,ou=People,dc=domain,dc=com
+cn: Daniel Ward
+sn: Ward
+givenname: Daniel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Sunnyvale
+uid: dward
+mail: dward@domain.com
+telephonenumber: +1 408 555 5322
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 3927
+userpassword: armload
+
+dn: uid=tward,ou=People,dc=domain,dc=com
+cn: Tobias Ward
+sn: Ward
+givenname: Tobias
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: tward
+mail: tward@domain.com
+telephonenumber: +1 408 555 7202
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 2238
+userpassword: cedilla
+
+dn: uid=pshelton,ou=People,dc=domain,dc=com
+cn: Patricia Shelton
+sn: Shelton
+givenname: Patricia
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Cupertino
+uid: pshelton
+mail: pshelton@domain.com
+telephonenumber: +1 408 555 6442
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 2918
+userpassword: nosedive
+
+dn: uid=jrentz,ou=People,dc=domain,dc=com
+cn: Jody Rentz
+sn: Rentz
+givenname: Jody
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: jrentz
+mail: jrentz@domain.com
+telephonenumber: +1 408 555 5829
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 3025
+userpassword: meander
+
+dn: uid=plorig,ou=People,dc=domain,dc=com
+cn: Peter Lorig
+sn: Lorig
+givenname: Peter
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: plorig
+mail: plorig@domain.com
+telephonenumber: +1 408 555 0624
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 1276
+userpassword: calorimeter
+
+dn: uid=ajensen,ou=People,dc=domain,dc=com
+cn: Allison Jensen
+sn: Jensen
+givenname: Allison
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: ajensen
+mail: ajensen@domain.com
+telephonenumber: +1 408 555 7892
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 0784
+userpassword: coltsfoot
+
+dn: uid=kschmith,ou=People,dc=domain,dc=com
+cn: Kelly Schmith
+sn: Schmith
+givenname: Kelly
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: kschmith
+mail: kschmith@domain.com
+telephonenumber: +1 408 555 9749
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 2221
+userpassword: purvey
+
+dn: uid=pworrell,ou=People,dc=domain,dc=com
+cn: Pete Worrell
+sn: Worrell
+givenname: Pete
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: pworrell
+mail: pworrell@domain.com
+telephonenumber: +1 408 555 1637
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 2449
+userpassword: solicitous
+
+dn: uid=mreuter,ou=People,dc=domain,dc=com
+cn: Matthew Reuter
+sn: Reuter
+givenname: Matthew
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: mreuter
+mail: mreuter@domain.com
+telephonenumber: +1 408 555 6879
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 1356
+userpassword: oblivious
+
+dn: uid=gtyler,ou=People,dc=domain,dc=com
+cn: Gern Tyler
+sn: Tyler
+givenname: Gern
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: gtyler
+mail: gtyler@domain.com
+telephonenumber: +1 408 555 1020
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0312
+userpassword: typology
+
+dn: uid=tschmith,ou=People,dc=domain,dc=com
+cn: Tobias Schmith
+sn: Schmith
+givenname: Tobias
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: tschmith
+mail: tschmith@domain.com
+telephonenumber: +1 408 555 9626
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 4607
+userpassword: compost
+
+dn: uid=bjense2,ou=People,dc=domain,dc=com
+cn: Bjorn Jensen
+sn: Jensen
+givenname: Bjorn
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: bjense2
+mail: bjense2@domain.com
+telephonenumber: +1 408 555 5655
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 4294
+userpassword: mortgage
+
+dn: uid=dswain,ou=People,dc=domain,dc=com
+cn: Dietrich Swain
+sn: Swain
+givenname: Dietrich
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Sunnyvale
+uid: dswain
+mail: dswain@domain.com
+telephonenumber: +1 408 555 9222
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 4396
+userpassword: freedom
+
+dn: uid=ahall,ou=People,dc=domain,dc=com
+cn: Andy Hall
+sn: Hall
+givenname: Andy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: ahall
+mail: ahall@domain.com
+telephonenumber: +1 408 555 6169
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 3050
+userpassword: slater
+
+dn: uid=jmuffly,ou=People,dc=domain,dc=com
+cn: Jeff Muffly
+sn: Muffly
+givenname: Jeff
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: jmuffly
+mail: jmuffly@domain.com
+telephonenumber: +1 408 555 5287
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 0997
+userpassword: dictate
+
+dn: uid=tjensen,ou=People,dc=domain,dc=com
+cn: Ted Jensen
+sn: Jensen
+givenname: Ted
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: tjensen
+mail: tjensen@domain.com
+telephonenumber: +1 408 555 8622
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 4717
+userpassword: ecosystem
+
+dn: uid=ahunter,ou=People,dc=domain,dc=com
+cn: Allison Hunter
+sn: Hunter
+givenname: Allison
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Sunnyvale
+uid: ahunter
+mail: ahunter@domain.com
+telephonenumber: +1 408 555 7713
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1213
+userpassword: egregious
+
+dn: uid=jgoldste,ou=People,dc=domain,dc=com
+cn: Jon Goldstein
+sn: Goldstein
+givenname: Jon
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: jgoldste
+mail: jgoldste@domain.com
+telephonenumber: +1 408 555 5769
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 1454
+userpassword: yellow
+
+dn: uid=aworrell,ou=People,dc=domain,dc=com
+cn: Alan Worrell
+sn: Worrell
+givenname: Alan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: aworrell
+mail: aworrell@domain.com
+telephonenumber: +1 408 555 1591
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 3966
+userpassword: gargoyle
+
+dn: uid=wlutz,ou=People,dc=domain,dc=com
+cn: Wendy Lutz
+sn: Lutz
+givenname: Wendy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: wlutz
+mail: wlutz@domain.com
+telephonenumber: +1 408 555 3358
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 4912
+userpassword: bassinet
+
+dn: uid=jlutz,ou=People,dc=domain,dc=com
+cn: Janet Lutz
+sn: Lutz
+givenname: Janet
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: jlutz
+mail: jlutz@domain.com
+telephonenumber: +1 408 555 4902
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 2544
+userpassword: autumn
+
+dn: uid=dlangdon,ou=People,dc=domain,dc=com
+cn: Dan Langdon
+sn: Langdon
+givenname: Dan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: dlangdon
+mail: dlangdon@domain.com
+telephonenumber: +1 408 555 7044
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 3263
+userpassword: botulin
+
+dn: uid=aknutson,ou=People,dc=domain,dc=com
+cn: Ashley Knutson
+sn: Knutson
+givenname: Ashley
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: aknutson
+mail: aknutson@domain.com
+telephonenumber: +1 408 555 2169
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 4736
+userpassword: maltose
+
+dn: uid=kmcinnis,ou=People,dc=domain,dc=com
+cn: Kelly Mcinnis
+sn: Mcinnis
+givenname: Kelly
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: kmcinnis
+mail: kmcinnis@domain.com
+telephonenumber: +1 408 555 8596
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 4312
+userpassword: stargaze
+
+dn: uid=tcouzens,ou=People,dc=domain,dc=com
+cn: Trent Couzens
+sn: Couzens
+givenname: Trent
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: tcouzens
+mail: tcouzens@domain.com
+telephonenumber: +1 408 555 8401
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 3994
+userpassword: tambourine
+
+dn: uid=lstockto,ou=People,dc=domain,dc=com
+cn: Lee Stockton
+sn: Stockton
+givenname: Lee
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: lstockto
+mail: lstockto@domain.com
+telephonenumber: +1 408 555 0518
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0169
+userpassword: brooklyn
+
+dn: uid=jbourke,ou=People,dc=domain,dc=com
+cn: Jon Bourke
+sn: Bourke
+givenname: Jon
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: jbourke
+mail: jbourke@domain.com
+telephonenumber: +1 408 555 8541
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0034
+userpassword: brainwash
+
+dn: uid=dlanoway,ou=People,dc=domain,dc=com
+cn: Dan Lanoway
+sn: Lanoway
+givenname: Dan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: dlanoway
+mail: dlanoway@domain.com
+telephonenumber: +1 408 555 2017
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 3540
+userpassword: manhattan
+
+dn: uid=kcope,ou=People,dc=domain,dc=com
+cn: Karl Cope
+sn: Cope
+givenname: Karl
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: kcope
+mail: kcope@domain.com
+telephonenumber: +1 408 555 2709
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 3040
+userpassword: forfeiture
+
+dn: uid=abarnes,ou=People,dc=domain,dc=com
+cn: Anne-Louise Barnes
+sn: Barnes
+givenname: Anne-Louise
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Santa Clara
+uid: abarnes
+mail: abarnes@domain.com
+telephonenumber: +1 408 555 9445
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 2290
+userpassword: chevron
+
+dn: uid=rjensen,ou=People,dc=domain,dc=com
+cn: Richard Jensen
+sn: Jensen
+givenname: Richard
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: rjensen
+mail: rjensen@domain.com
+telephonenumber: +1 408 555 5957
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 2631
+userpassword: disciplinarian
+
+dn: uid=phun2,ou=People,dc=domain,dc=com
+cn: Pete Hunt
+sn: Hunt
+givenname: Pete
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: phun2
+mail: phun2@domain.com
+telephonenumber: +1 408 555 0342
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 0087
+userpassword: absorb
+
+dn: uid=mvaughan,ou=People,dc=domain,dc=com
+cn: Matthew Vaughan
+sn: Vaughan
+givenname: Matthew
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Sunnyvale
+uid: mvaughan
+mail: mvaughan@domain.com
+telephonenumber: +1 408 555 4692
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 4508
+userpassword: submitted
+
+dn: uid=jlut2,ou=People,dc=domain,dc=com
+cn: James Lutz
+sn: Lutz
+givenname: James
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: jlut2
+mail: jlut2@domain.com
+telephonenumber: +1 408 555 9689
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 3541
+userpassword: shrank
+
+dn: uid=mjablons,ou=People,dc=domain,dc=com
+cn: Morgan Jablonski
+sn: Jablonski
+givenname: Morgan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: mjablons
+mail: mjablons@domain.com
+telephonenumber: +1 408 555 0813
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 3160
+userpassword: minimal
+
+dn: uid=pchassin,ou=People,dc=domain,dc=com
+cn: Peter Chassin
+sn: Chassin
+givenname: Peter
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Santa Clara
+uid: pchassin
+mail: pchassin@domain.com
+telephonenumber: +1 408 555 2816
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 4524
+userpassword: barbital
+
+dn: uid=dcope,ou=People,dc=domain,dc=com
+cn: Dan Cope
+sn: Cope
+givenname: Dan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Sunnyvale
+uid: dcope
+mail: dcope@domain.com
+telephonenumber: +1 408 555 9813
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 1737
+userpassword: snifter
+
+dn: uid=jrent2,ou=People,dc=domain,dc=com
+cn: Judy Rentz
+sn: Rentz
+givenname: Judy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Santa Clara
+uid: jrent2
+mail: jrent2@domain.com
+telephonenumber: +1 408 555 2523
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 4405
+userpassword: tachistoscope
+
+dn: uid=tcruse,ou=People,dc=domain,dc=com
+cn: Tobias Cruse
+sn: Cruse
+givenname: Tobias
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: tcruse
+mail: tcruse@domain.com
+telephonenumber: +1 408 555 5980
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 4191
+userpassword: flinty
+
+dn: uid=eward,ou=People,dc=domain,dc=com
+cn: Eric Ward
+sn: Ward
+givenname: Eric
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: eward
+mail: eward@domain.com
+telephonenumber: +1 408 555 2320
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 4874
+userpassword: episcopal
+
+dn: uid=ttully,ou=People,dc=domain,dc=com
+cn: Torrey Tully
+sn: Tully
+givenname: Torrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: ttully
+mail: ttully@domain.com
+telephonenumber: +1 408 555 2274
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 3924
+userpassword: schooner
+
+dn: uid=charvey,ou=People,dc=domain,dc=com
+cn: Cecil Harvey
+sn: Harvey
+givenname: Cecil
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: charvey
+mail: charvey@domain.com
+telephonenumber: +1 408 555 1815
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 4583
+userpassword: journalese
+
+dn: uid=rfisher,ou=People,dc=domain,dc=com
+cn: Randy Fisher
+sn: Fisher
+givenname: Randy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: rfisher
+mail: rfisher@domain.com
+telephonenumber: +1 408 555 1506
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 1579
+userpassword: pomegranate
+
+dn: uid=alangdon,ou=People,dc=domain,dc=com
+cn: Andrew Langdon
+sn: Langdon
+givenname: Andrew
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: alangdon
+mail: alangdon@domain.com
+telephonenumber: +1 408 555 8289
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 2254
+userpassword: muzzle
+
+dn: uid=drose,ou=People,dc=domain,dc=com
+cn: David Rose
+sn: Rose
+givenname: David
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Sunnyvale
+uid: drose
+mail: drose@domain.com
+telephonenumber: +1 408 555 3963
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 4012
+userpassword: gubernatorial
+
+dn: uid=polfield,ou=People,dc=domain,dc=com
+cn: Peter Olfield
+sn: Olfield
+givenname: Peter
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: polfield
+mail: polfield@domain.com
+telephonenumber: +1 408 555 8231
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1376
+userpassword: monologue
+
+dn: uid=awalker,ou=People,dc=domain,dc=com
+cn: Andy Walker
+sn: Walker
+givenname: Andy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: awalker
+mail: awalker@domain.com
+telephonenumber: +1 408 555 9199
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 0061
+userpassword: detonable
+
+dn: uid=lrentz,ou=People,dc=domain,dc=com
+cn: Lex Rentz
+sn: Rentz
+givenname: Lex
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: lrentz
+mail: lrentz@domain.com
+telephonenumber: +1 408 555 2019
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 2203
+userpassword: calcium
+
+dn: uid=jvaughan,ou=People,dc=domain,dc=com
+cn: Jeff Vaughan
+sn: Vaughan
+givenname: Jeff
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: jvaughan
+mail: jvaughan@domain.com
+telephonenumber: +1 408 555 4543
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 1734
+userpassword: appoint
+
+dn: uid=bfrancis,ou=People,dc=domain,dc=com
+cn: Barbara Francis
+sn: Francis
+givenname: Barbara
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: bfrancis
+mail: bfrancis@domain.com
+telephonenumber: +1 408 555 9111
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 3743
+userpassword: holystone
+
+dn: uid=ewalker,ou=People,dc=domain,dc=com
+cn: Eric Walker
+sn: Walker
+givenname: Eric
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Cupertino
+uid: ewalker
+mail: ewalker@domain.com
+telephonenumber: +1 408 555 6387
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 2295
+userpassword: beguile
+
+dn: uid=tjames,ou=People,dc=domain,dc=com
+cn: Tobias James
+sn: James
+givenname: Tobias
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: tjames
+mail: tjames@domain.com
+telephonenumber: +1 408 555 2458
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 0730
+userpassword: turtle
+
+dn: uid=brigden,ou=People,dc=domain,dc=com
+cn: Bjorn Rigden
+sn: Rigden
+givenname: Bjorn
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: brigden
+mail: brigden@domain.com
+telephonenumber: +1 408 555 5263
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 1643
+userpassword: purple
+
+dn: uid=ecruse,ou=People,dc=domain,dc=com
+cn: Eric Cruse
+sn: Cruse
+givenname: Eric
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: ecruse
+mail: ecruse@domain.com
+telephonenumber: +1 408 555 0648
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 4233
+userpassword: platelet
+
+dn: uid=rjense2,ou=People,dc=domain,dc=com
+cn: Randy Jensen
+sn: Jensen
+givenname: Randy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Sunnyvale
+uid: rjense2
+mail: rjense2@domain.com
+telephonenumber: +1 408 555 9045
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 1984
+userpassword: transpose
+
+dn: uid=rhunt,ou=People,dc=domain,dc=com
+cn: Richard Hunt
+sn: Hunt
+givenname: Richard
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: rhunt
+mail: rhunt@domain.com
+telephonenumber: +1 408 555 0139
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 0718
+userpassword: becloud
+
+dn: uid=bparker,ou=People,dc=domain,dc=com
+cn: Barry Parker
+sn: Parker
+givenname: Barry
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Sunnyvale
+uid: bparker
+mail: bparker@domain.com
+telephonenumber: +1 408 555 4647
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 1148
+userpassword: lenticular
+
+dn: uid=ealexand,ou=People,dc=domain,dc=com
+cn: Erin Alexander
+sn: Alexander
+givenname: Erin
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: ealexand
+mail: ealexand@domain.com
+telephonenumber: +1 408 555 5563
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 2434
+userpassword: galactose
+
+dn: uid=mtyler,ou=People,dc=domain,dc=com
+cn: Matthew Tyler
+sn: Tyler
+givenname: Matthew
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: mtyler
+mail: mtyler@domain.com
+telephonenumber: +1 408 555 7907
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 2701
+userpassword: instantiate
+
+dn: uid=elott,ou=People,dc=domain,dc=com
+cn: Emanuel Lott
+sn: Lott
+givenname: Emanuel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: elott
+mail: elott@domain.com
+telephonenumber: +1 408 555 0932
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 3906
+userpassword: holdout
+
+dn: uid=cnewport,ou=People,dc=domain,dc=com
+cn: Christoph Newport
+sn: Newport
+givenname: Christoph
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Sunnyvale
+uid: cnewport
+mail: cnewport@domain.com
+telephonenumber: +1 408 555 0066
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 0056
+userpassword: expertise
+
+dn: uid=jvedder,ou=People,dc=domain,dc=com
+cn: Jeff Vedder
+sn: Vedder
+givenname: Jeff
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: jvedder
+mail: jvedder@domain.com
+telephonenumber: +1 408 555 4668
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 3445
+userpassword: befitting
+
+dn: cn=Accounting Managers,ou=Groups,dc=domain,dc=com
+objectclass: top
+objectclass: groupOfUniqueNames
+cn: Accounting Managers
+ou: Groups
+uniquemember: uid=scarter,ou=People,dc=domain,dc=com
+uniquemember: uid=tmorris,ou=People,dc=domain,dc=com
+description: People who can manage accounting entries
+
+dn: cn=HR Managers,ou=Groups,dc=domain,dc=com
+objectclass: top
+objectclass: groupOfUniqueNames
+cn: HR Managers
+ou: Groups
+uniquemember: uid=kvaughan,ou=People,dc=domain,dc=com
+uniquemember: uid=cschmith,ou=People,dc=domain,dc=com
+description: People who can manage HR entries
+
+dn: cn=QA Managers,ou=Groups,dc=domain,dc=com
+objectclass: top
+objectclass: groupOfUniqueNames
+cn: QA Managers
+ou: Groups
+uniquemember: uid=abergin,ou=People,dc=domain,dc=com
+uniquemember: uid=jwalker,ou=People,dc=domain,dc=com
+description: People who can manage QA entries
+
+dn: cn=PD Managers,ou=Groups,dc=domain,dc=com
+objectclass: top
+objectclass: groupOfUniqueNames
+cn: PD Managers
+ou: Groups
+uniquemember: uid=kwinters,ou=People,dc=domain,dc=com
+uniquemember: uid=trigden,ou=People,dc=domain,dc=com
+description: People who can manage engineer entries
+
+dn: ou=Netscape Servers,dc=domain,dc=com
+objectclass: top
+objectclass: organizationalUnit
+ou: Netscape Servers
+description: Standard branch for Netscape Server registration
+
Added: incubator/directory/eve/branches/start/src/ldif/ori_example.ldif
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/ldif/ori_example.ldif Thu Jun 24 00:06:35 2004
@@ -0,0 +1,2786 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# dc=example,dc=com sample LDIF file
+#
+# Notes:
+# 158 total entries.
+# - (objectclass=domain) entry (dc=example,dc=com). (Automatically created for suffix)
+# 3 (objectclass=organizationalunit) entries.
+# 5 (objectclass=groupofuniquenames) entries.
+# 150 (objectclass=person) entries (all under ou=people,dc=example,dc=com).
+#
+
+dn: ou=Groups, dc=example,dc=com
+objectclass: top
+objectclass: organizationalunit
+ou: Groups
+
+dn: cn=Directory Administrators, ou=Groups, dc=example,dc=com
+cn: Directory Administrators
+objectclass: top
+objectclass: groupofuniquenames
+ou: Groups
+uniquemember: uid=kvaughan, ou=People, dc=example,dc=com
+uniquemember: uid=rdaugherty, ou=People, dc=example,dc=com
+uniquemember: uid=hmiller, ou=People, dc=example,dc=com
+
+dn: ou=People, dc=example,dc=com
+objectclass: top
+objectclass: organizationalunit
+ou: People
+
+dn: ou=Special Users,dc=example,dc=com
+objectclass: top
+objectclass: organizationalUnit
+ou: Special Users
+description: Special Administrative Accounts
+
+dn: uid=scarter, ou=People, dc=example,dc=com
+cn: Sam Carter
+sn: Carter
+givenname: Sam
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: scarter
+mail: scarter@example.com
+telephonenumber: +1 408 555 4798
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 4612
+userpassword: sprain
+
+dn: uid=tmorris, ou=People, dc=example,dc=com
+cn: Ted Morris
+sn: Morris
+givenname: Ted
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: tmorris
+mail: tmorris@example.com
+telephonenumber: +1 408 555 9187
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 4117
+userpassword: irrefutable
+
+dn: uid=kvaughan, ou=People, dc=example,dc=com
+cn: Kirsten Vaughan
+sn: Vaughan
+givenname: Kirsten
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: kvaughan
+mail: kvaughan@example.com
+telephonenumber: +1 408 555 5625
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 2871
+userpassword: bribery
+# Kirsten is a Directory Administrator and therefore should not
+# be subject to any resource limits.
+
+dn: uid=abergin, ou=People, dc=example,dc=com
+cn: Andy Bergin
+sn: Bergin
+givenname: Andy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Cupertino
+uid: abergin
+mail: abergin@example.com
+telephonenumber: +1 408 555 8585
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 3472
+userpassword: inflict
+
+dn: uid=dmiller, ou=People, dc=example,dc=com
+cn: David Miller
+sn: Miller
+givenname: David
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: dmiller
+mail: dmiller@example.com
+telephonenumber: +1 408 555 9423
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 4135
+userpassword: gosling
+
+dn: uid=gfarmer, ou=People, dc=example,dc=com
+cn: Gern Farmer
+sn: Farmer
+givenname: Gern
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: gfarmer
+mail: gfarmer@example.com
+telephonenumber: +1 408 555 6201
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1269
+userpassword: ruling
+
+dn: uid=kwinters, ou=People, dc=example,dc=com
+cn: Kelly Winters
+sn: Winters
+givenname: Kelly
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: kwinters
+mail: kwinters@example.com
+telephonenumber: +1 408 555 9069
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 4178
+userpassword: forsook
+
+dn: uid=trigden, ou=People, dc=example,dc=com
+cn: Torrey Rigden
+sn: Rigden
+givenname: Torrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: trigden
+mail: trigden@example.com
+telephonenumber: +1 408 555 9280
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 3584
+userpassword: sensitive
+
+dn: uid=cschmith, ou=People, dc=example,dc=com
+cn: Chris Schmith
+sn: Schmith
+givenname: Chris
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: cschmith
+mail: cschmith@example.com
+telephonenumber: +1 408 555 8011
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0416
+userpassword: hypotenuse
+
+
+dn: uid=jwallace, ou=People, dc=example,dc=com
+cn: Judy Wallace
+sn: Wallace
+givenname: Judy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: jwallace
+mail: jwallace@example.com
+telephonenumber: +1 408 555 0319
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1033
+userpassword: linear
+
+dn: uid=jwalker, ou=People, dc=example,dc=com
+cn: John Walker
+sn: Walker
+givenname: John
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Cupertino
+uid: jwalker
+mail: jwalker@example.com
+telephonenumber: +1 408 555 1476
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 3915
+userpassword: dogleg
+
+dn: uid=tclow, ou=People, dc=example,dc=com
+cn: Torrey Clow
+sn: Clow
+givenname: Torrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: tclow
+mail: tclow@example.com
+telephonenumber: +1 408 555 8825
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 4376
+userpassword: cardreader
+
+dn: uid=rdaugherty, ou=People, dc=example,dc=com
+cn: Robert Daugherty
+sn: Daugherty
+givenname: Robert
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: rdaugherty
+mail: rdaugherty@example.com
+telephonenumber: +1 408 555 1296
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 0194
+userpassword: apples
+# Robert is a Directory Administrator and therefore should not
+# be subject to any resource limits.
+
+dn: uid=jreuter, ou=People, dc=example,dc=com
+cn: Jayne Reuter
+sn: Reuter
+givenname: Jayne
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Cupertino
+uid: jreuter
+mail: jreuter@example.com
+telephonenumber: +1 408 555 1122
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 2942
+userpassword: destroy
+
+dn: uid=tmason, ou=People, dc=example,dc=com
+cn: Torrey Mason
+sn: Mason
+givenname: Torrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: tmason
+mail: tmason@example.com
+telephonenumber: +1 408 555 1596
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 1124
+userpassword: squatted
+
+dn: uid=bhall, ou=People, dc=example,dc=com
+cn: Benjamin Hall
+sn: Hall
+givenname: Benjamin
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: bhall
+mail: bhall@example.com
+telephonenumber: +1 408 555 6067
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 2511
+userpassword: oranges
+
+dn: uid=btalbot, ou=People, dc=example,dc=com
+cn: Brad Talbot
+sn: Talbot
+givenname: Brad
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: btalbot
+mail: btalbot@example.com
+telephonenumber: +1 408 555 4992
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 3532
+userpassword: trident
+
+dn: uid=mward, ou=People, dc=example,dc=com
+cn: Marcus Ward
+sn: Ward
+givenname: Marcus
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: mward
+mail: mward@example.com
+telephonenumber: +1 408 555 5688
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 1707
+userpassword: normal
+
+dn: uid=bjablons, ou=People, dc=example,dc=com
+cn: Barbara Jablonski
+sn: Jablonski
+givenname: Barbara
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: bjablons
+mail: bjablons@example.com
+telephonenumber: +1 408 555 8815
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0906
+userpassword: strawberry
+
+dn: uid=jmcFarla, ou=People, dc=example,dc=com
+cn: Judy McFarland
+sn: McFarland
+givenname: Judy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: jmcFarla
+mail: jmcFarla@example.com
+telephonenumber: +1 408 555 2567
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 2359
+userpassword: walnut
+
+dn: uid=llabonte, ou=People, dc=example,dc=com
+cn: Lee Labonte
+sn: Labonte
+givenname: Lee
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: llabonte
+mail: llabonte@example.com
+telephonenumber: +1 408 555 0957
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 2854
+userpassword: sourdough
+
+dn: uid=jcampaig, ou=People, dc=example,dc=com
+cn: Jody Campaigne
+sn: Campaigne
+givenname: Jody
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: jcampaig
+mail: jcampaig@example.com
+telephonenumber: +1 408 555 1660
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 4385
+userpassword: grapevine
+
+dn: uid=bhal2, ou=People, dc=example,dc=com
+cn: Barbara Hall
+sn: Hall
+givenname: Barbara
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: bhal2
+mail: bhal2@example.com
+telephonenumber: +1 408 555 4491
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 2758
+userpassword: truths
+
+dn: uid=alutz, ou=People, dc=example,dc=com
+cn: Alexander Lutz
+sn: Lutz
+givenname: Alexander
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: alutz
+mail: alutz@example.com
+telephonenumber: +1 408 555 6505
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 1327
+userpassword: northward
+
+dn: uid=btalbo2, ou=People, dc=example,dc=com
+cn: Bjorn Talbot
+sn: Talbot
+givenname: Bjorn
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: btalbo2
+mail: btalbo2@example.com
+telephonenumber: +1 408 555 4234
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 1205
+userpassword: corduroy
+
+dn: uid=achassin, ou=People, dc=example,dc=com
+cn: Ashley Chassin
+sn: Chassin
+givenname: Ashley
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Santa Clara
+uid: achassin
+mail: achassin@example.com
+telephonenumber: +1 408 555 9972
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 0466
+userpassword: duopolist
+
+dn: uid=hmiller, ou=People, dc=example,dc=com
+cn: Harry Miller
+sn: Miller
+givenname: Harry
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: hmiller
+mail: hmiller@example.com
+telephonenumber: +1 408 555 9804
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 4304
+userpassword: hillock
+# Harry is a Directory Administrator and therefore should not
+# be subject to any resource limits.
+
+dn: uid=jcampai2, ou=People, dc=example,dc=com
+cn: Jeffrey Campaigne
+sn: Campaigne
+givenname: Jeffrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: jcampai2
+mail: jcampai2@example.com
+telephonenumber: +1 408 555 7393
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 1377
+userpassword: nominee
+
+dn: uid=lulrich, ou=People, dc=example,dc=com
+cn: Lee Ulrich
+sn: Ulrich
+givenname: Lee
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Sunnyvale
+uid: lulrich
+mail: lulrich@example.com
+telephonenumber: +1 408 555 8652
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 0985
+userpassword: attribution
+
+dn: uid=mlangdon, ou=People, dc=example,dc=com
+cn: Marcus Langdon
+sn: Langdon
+givenname: Marcus
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: mlangdon
+mail: mlangdon@example.com
+telephonenumber: +1 408 555 6249
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 4471
+userpassword: threat
+
+dn: uid=striplet, ou=People, dc=example,dc=com
+cn: Stephen Triplett
+sn: Triplett
+givenname: Stephen
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: striplet
+mail: striplet@example.com
+telephonenumber: +1 408 555 4519
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 3083
+userpassword: compactify
+
+dn: uid=gtriplet, ou=People, dc=example,dc=com
+cn: Gern Triplett
+sn: Triplett
+givenname: Gern
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: gtriplet
+mail: gtriplet@example.com
+telephonenumber: +1 408 555 2582
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 4023
+userpassword: placeable
+
+dn: uid=jfalena, ou=People, dc=example,dc=com
+cn: John Falena
+sn: Falena
+givenname: John
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: jfalena
+mail: jfalena@example.com
+telephonenumber: +1 408 555 8133
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 1917
+userpassword: nightly
+
+dn: uid=speterso, ou=People, dc=example,dc=com
+cn: Sue Peterson
+sn: Peterson
+givenname: Sue
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: speterso
+mail: speterso@example.com
+telephonenumber: +1 408 555 3613
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 3073
+userpassword: quinine
+
+dn: uid=ejohnson, ou=People, dc=example,dc=com
+cn: Emanuel Johnson
+sn: Johnson
+givenname: Emanuel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: ejohnson
+mail: ejohnson@example.com
+telephonenumber: +1 408 555 3287
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 3737
+userpassword: marketwise
+
+dn: uid=prigden, ou=People, dc=example,dc=com
+cn: Peter Rigden
+sn: Rigden
+givenname: Peter
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: prigden
+mail: prigden@example.com
+telephonenumber: +1 408 555 5099
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1271
+userpassword: epiphyseal
+
+dn: uid=bwalker, ou=People, dc=example,dc=com
+cn: Brad Walker
+sn: Walker
+givenname: Brad
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: bwalker
+mail: bwalker@example.com
+telephonenumber: +1 408 555 5476
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 3529
+userpassword: interruptible
+
+dn: uid=kjensen, ou=People, dc=example,dc=com
+cn: Kurt Jensen
+sn: Jensen
+givenname: Kurt
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: kjensen
+mail: kjensen@example.com
+telephonenumber: +1 408 555 6127
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 1944
+userpassword: regulatory
+
+dn: uid=mlott, ou=People, dc=example,dc=com
+cn: Mike Lott
+sn: Lott
+givenname: Mike
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: mlott
+mail: mlott@example.com
+telephonenumber: +1 408 555 2234
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 0498
+userpassword: cognac
+
+dn: uid=cwallace, ou=People, dc=example,dc=com
+cn: Cecil Wallace
+sn: Wallace
+givenname: Cecil
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: cwallace
+mail: cwallace@example.com
+telephonenumber: +1 408 555 6438
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 0349
+userpassword: quintus
+
+dn: uid=tpierce, ou=People, dc=example,dc=com
+cn: Tobias Pierce
+sn: Pierce
+givenname: Tobias
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: tpierce
+mail: tpierce@example.com
+telephonenumber: +1 408 555 1531
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 1383
+userpassword: rascal
+
+dn: uid=rbannist, ou=People, dc=example,dc=com
+cn: Richard Bannister
+sn: Bannister
+givenname: Richard
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: rbannist
+mail: rbannist@example.com
+telephonenumber: +1 408 555 1833
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 0983
+userpassword: demonstrate
+
+dn: uid=bplante, ou=People, dc=example,dc=com
+cn: Brian Plante
+sn: Plante
+givenname: Brian
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: bplante
+mail: bplante@example.com
+telephonenumber: +1 408 555 3550
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 4654
+userpassword: tangerine
+
+dn: uid=rmills, ou=People, dc=example,dc=com
+cn: Randy Mills
+sn: Mills
+givenname: Randy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: rmills
+mail: rmills@example.com
+telephonenumber: +1 408 555 2072
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 3823
+userpassword: condescend
+
+dn: uid=bschneid, ou=People, dc=example,dc=com
+cn: Benjamin Schneider
+sn: Schneider
+givenname: Benjamin
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: bschneid
+mail: bschneid@example.com
+telephonenumber: +1 408 555 1012
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 4471
+userpassword: biblical
+
+dn: uid=skellehe, ou=People, dc=example,dc=com
+cn: Sue Kelleher
+sn: Kelleher
+givenname: Sue
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Santa Clara
+uid: skellehe
+mail: skellehe@example.com
+telephonenumber: +1 408 555 3480
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 1608
+userpassword: sweltering
+
+dn: uid=brentz, ou=People, dc=example,dc=com
+cn: Bertram Rentz
+sn: Rentz
+givenname: Bertram
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Sunnyvale
+uid: brentz
+mail: brentz@example.com
+telephonenumber: +1 408 555 5526
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 0617
+userpassword: diachronic
+
+dn: uid=dsmith, ou=People, dc=example,dc=com
+cn: Daniel Smith
+sn: Smith
+givenname: Daniel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: dsmith
+mail: dsmith@example.com
+telephonenumber: +1 408 555 9519
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 0368
+userpassword: quantitative
+
+dn: uid=scarte2, ou=People, dc=example,dc=com
+cn: Stephen Carter
+sn: Carter
+givenname: Stephen
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: scarte2
+mail: scarte2@example.com
+telephonenumber: +1 408 555 6022
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 2013
+userpassword: scooter
+
+dn: uid=dthorud, ou=People, dc=example,dc=com
+cn: David Thorud
+sn: Thorud
+givenname: David
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: dthorud
+mail: dthorud@example.com
+telephonenumber: +1 408 555 6185
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 1128
+userpassword: fulcrum
+
+dn: uid=ekohler, ou=People, dc=example,dc=com
+cn: Elba Kohler
+sn: Kohler
+givenname: Elba
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: ekohler
+mail: ekohler@example.com
+telephonenumber: +1 408 555 1926
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 2721
+userpassword: guildhall
+
+dn: uid=lcampbel, ou=People, dc=example,dc=com
+cn: Laurel Campbell
+sn: Campbell
+givenname: Laurel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: lcampbel
+mail: lcampbel@example.com
+telephonenumber: +1 408 555 2537
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 2073
+userpassword: impress
+
+dn: uid=tlabonte, ou=People, dc=example,dc=com
+cn: Tim Labonte
+sn: Labonte
+givenname: Tim
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: tlabonte
+mail: tlabonte@example.com
+telephonenumber: +1 408 555 0058
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 1426
+userpassword: express
+
+dn: uid=slee, ou=People, dc=example,dc=com
+cn: Scott Lee
+sn: Lee
+givenname: Scott
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: slee
+mail: slee@example.com
+telephonenumber: +1 408 555 2335
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 1806
+userpassword: revertive
+
+dn: uid=bfree, ou=People, dc=example,dc=com
+cn: Bjorn Free
+sn: Free
+givenname: Bjorn
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: bfree
+mail: bfree@example.com
+telephonenumber: +1 408 555 8588
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 3307
+userpassword: etiquette
+
+dn: uid=tschneid, ou=People, dc=example,dc=com
+cn: Torrey Schneider
+sn: Schneider
+givenname: Torrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: tschneid
+mail: tschneid@example.com
+telephonenumber: +1 408 555 7086
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 2292
+userpassword: chaperone
+
+dn: uid=prose, ou=People, dc=example,dc=com
+cn: Paula Rose
+sn: Rose
+givenname: Paula
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: prose
+mail: prose@example.com
+telephonenumber: +1 408 555 9998
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 0542
+userpassword: regatta
+
+dn: uid=jhunter, ou=People, dc=example,dc=com
+cn: Janet Hunter
+sn: Hunter
+givenname: Janet
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: jhunter
+mail: jhunter@example.com
+telephonenumber: +1 408 555 7665
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 4856
+userpassword: nanometer
+
+dn: uid=ashelton, ou=People, dc=example,dc=com
+cn: Alexander Shelton
+sn: Shelton
+givenname: Alexander
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: ashelton
+mail: ashelton@example.com
+telephonenumber: +1 408 555 1081
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 1987
+userpassword: appointe
+
+dn: uid=mmcinnis, ou=People, dc=example,dc=com
+cn: Marcus Mcinnis
+sn: Mcinnis
+givenname: Marcus
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: mmcinnis
+mail: mmcinnis@example.com
+telephonenumber: +1 408 555 9655
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 4818
+userpassword: calcify
+
+dn: uid=falbers, ou=People, dc=example,dc=com
+cn: Frank Albers
+sn: Albers
+givenname: Frank
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: falbers
+mail: falbers@example.com
+telephonenumber: +1 408 555 3094
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 1439
+userpassword: degradation
+
+dn: uid=mschneid, ou=People, dc=example,dc=com
+cn: Martin Schneider
+sn: Schneider
+givenname: Martin
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: mschneid
+mail: mschneid@example.com
+telephonenumber: +1 408 555 5017
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 3153
+userpassword: motorcycle
+
+dn: uid=pcruse, ou=People, dc=example,dc=com
+cn: Patricia Cruse
+sn: Cruse
+givenname: Patricia
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: pcruse
+mail: pcruse@example.com
+telephonenumber: +1 408 555 8641
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 3967
+userpassword: pauper
+
+dn: uid=tkelly, ou=People, dc=example,dc=com
+cn: Timothy Kelly
+sn: Kelly
+givenname: Timothy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Santa Clara
+uid: tkelly
+mail: tkelly@example.com
+telephonenumber: +1 408 555 4295
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 3107
+userpassword: risible
+
+dn: uid=ahel, ou=People, dc=example,dc=com
+cn: Andrew Hel
+sn: Hel
+givenname: Andrew
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: ahel
+mail: ahel@example.com
+telephonenumber: +1 408 555 2666
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 0572
+userpassword: sarsaparilla
+
+dn: uid=jburrell, ou=People, dc=example,dc=com
+cn: James Burrell
+sn: Burrell
+givenname: James
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: jburrell
+mail: jburrell@example.com
+telephonenumber: +1 408 555 0751
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 4926
+userpassword: degrease
+
+dn: uid=smason, ou=People, dc=example,dc=com
+cn: Sue Mason
+sn: Mason
+givenname: Sue
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: smason
+mail: smason@example.com
+telephonenumber: +1 408 555 9780
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 4971
+userpassword: sensible
+
+dn: uid=ptyler, ou=People, dc=example,dc=com
+cn: Pete Tyler
+sn: Tyler
+givenname: Pete
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: ptyler
+mail: ptyler@example.com
+telephonenumber: +1 408 555 3335
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0327
+userpassword: vinegar
+
+dn: uid=calexand, ou=People, dc=example,dc=com
+cn: Chris Alexander
+sn: Alexander
+givenname: Chris
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Sunnyvale
+uid: calexand
+mail: calexand@example.com
+telephonenumber: +1 408 555 9438
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 2884
+userpassword: dauphin
+
+dn: uid=jcruse, ou=People, dc=example,dc=com
+cn: Jim Cruse
+sn: Cruse
+givenname: Jim
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Santa Clara
+uid: jcruse
+mail: jcruse@example.com
+telephonenumber: +1 408 555 9482
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 0083
+userpassword: bridgework
+
+dn: uid=kcarter, ou=People, dc=example,dc=com
+cn: Karen Carter
+sn: Carter
+givenname: Karen
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: kcarter
+mail: kcarter@example.com
+telephonenumber: +1 408 555 4675
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 2320
+userpassword: radiosonde
+
+dn: uid=rfish, ou=People, dc=example,dc=com
+cn: Randy Fish
+sn: Fish
+givenname: Randy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: rfish
+mail: rfish@example.com
+telephonenumber: +1 408 555 9865
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 2317
+userpassword: mailbox
+
+dn: uid=phunt, ou=People, dc=example,dc=com
+cn: Philip Hunt
+sn: Hunt
+givenname: Philip
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: phunt
+mail: phunt@example.com
+telephonenumber: +1 408 555 1242
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 1183
+userpassword: wastewater
+
+dn: uid=rschneid, ou=People, dc=example,dc=com
+cn: Rachel Schneider
+sn: Schneider
+givenname: Rachel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: rschneid
+mail: rschneid@example.com
+telephonenumber: +1 408 555 9908
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 4183
+userpassword: decorous
+
+dn: uid=bjensen, ou=People, dc=example,dc=com
+cn: Barbara Jensen
+cn: Babs Jensen
+sn: Jensen
+givenname: Barbara
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: bjensen
+mail: bjensen@example.com
+telephonenumber: +1 408 555 1862
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 0209
+userpassword: hifalutin
+
+dn: uid=jlange, ou=People, dc=example,dc=com
+cn: Jim Lange
+sn: Lange
+givenname: Jim
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: jlange
+mail: jlange@example.com
+telephonenumber: +1 408 555 0488
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 3798
+userpassword: chastity
+
+dn: uid=rulrich, ou=People, dc=example,dc=com
+cn: Randy Ulrich
+sn: Ulrich
+givenname: Randy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: rulrich
+mail: rulrich@example.com
+telephonenumber: +1 408 555 5311
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 1282
+userpassword: twinkle
+
+dn: uid=rfrancis, ou=People, dc=example,dc=com
+cn: Richard Francis
+sn: Francis
+givenname: Richard
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: rfrancis
+mail: rfrancis@example.com
+telephonenumber: +1 408 555 8157
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 3482
+userpassword: hacienda
+
+dn: uid=mwhite, ou=People, dc=example,dc=com
+cn: Morgan White
+sn: White
+givenname: Morgan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: mwhite
+mail: mwhite@example.com
+telephonenumber: +1 408 555 9620
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 3088
+userpassword: staple
+
+dn: uid=gjensen, ou=People, dc=example,dc=com
+cn: Gern Jensen
+sn: Jensen
+givenname: Gern
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: gjensen
+mail: gjensen@example.com
+telephonenumber: +1 408 555 3299
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 4609
+userpassword: primitive
+
+dn: uid=awhite, ou=People, dc=example,dc=com
+cn: Alan White
+sn: White
+givenname: Alan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Sunnyvale
+uid: awhite
+mail: awhite@example.com
+telephonenumber: +1 408 555 3232
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 0142
+userpassword: placeholder
+
+dn: uid=bmaddox, ou=People, dc=example,dc=com
+cn: Barbara Maddox
+sn: Maddox
+givenname: Barbara
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: bmaddox
+mail: bmaddox@example.com
+telephonenumber: +1 408 555 7783
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 2207
+userpassword: feedback
+
+dn: uid=mtalbot, ou=People, dc=example,dc=com
+cn: Martin Talbot
+sn: Talbot
+givenname: Martin
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: mtalbot
+mail: mtalbot@example.com
+telephonenumber: +1 408 555 9228
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1415
+userpassword: currant
+
+dn: uid=jbrown, ou=People, dc=example,dc=com
+cn: Judy Brown
+sn: Brown
+givenname: Judy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Santa Clara
+uid: jbrown
+mail: jbrown@example.com
+telephonenumber: +1 408 555 6885
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 4224
+userpassword: militiamen
+
+dn: uid=jjensen, ou=People, dc=example,dc=com
+cn: Jody Jensen
+sn: Jensen
+givenname: Jody
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: jjensen
+mail: jjensen@example.com
+telephonenumber: +1 408 555 7587
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 4882
+userpassword: borderland
+
+dn: uid=mcarter, ou=People, dc=example,dc=com
+cn: Mike Carter
+sn: Carter
+givenname: Mike
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: mcarter
+mail: mcarter@example.com
+telephonenumber: +1 408 555 1846
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 3819
+userpassword: mainland
+
+dn: uid=dakers, ou=People, dc=example,dc=com
+cn: David Akers
+sn: Akers
+givenname: David
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: dakers
+mail: dakers@example.com
+telephonenumber: +1 408 555 4812
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 4944
+userpassword: integument
+
+dn: uid=sfarmer, ou=People, dc=example,dc=com
+cn: Scott Farmer
+sn: Farmer
+givenname: Scott
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: sfarmer
+mail: sfarmer@example.com
+telephonenumber: +1 408 555 4228
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 0019
+userpassword: triumphal
+
+dn: uid=dward, ou=People, dc=example,dc=com
+cn: Daniel Ward
+sn: Ward
+givenname: Daniel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Sunnyvale
+uid: dward
+mail: dward@example.com
+telephonenumber: +1 408 555 5322
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 3927
+userpassword: armload
+
+dn: uid=tward, ou=People, dc=example,dc=com
+cn: Tobias Ward
+sn: Ward
+givenname: Tobias
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: tward
+mail: tward@example.com
+telephonenumber: +1 408 555 7202
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 2238
+userpassword: cedilla
+
+dn: uid=pshelton, ou=People, dc=example,dc=com
+cn: Patricia Shelton
+sn: Shelton
+givenname: Patricia
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Cupertino
+uid: pshelton
+mail: pshelton@example.com
+telephonenumber: +1 408 555 6442
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 2918
+userpassword: nosedive
+
+dn: uid=jrentz, ou=People, dc=example,dc=com
+cn: Jody Rentz
+sn: Rentz
+givenname: Jody
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: jrentz
+mail: jrentz@example.com
+telephonenumber: +1 408 555 5829
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 3025
+userpassword: meander
+
+dn: uid=plorig, ou=People, dc=example,dc=com
+cn: Peter Lorig
+sn: Lorig
+givenname: Peter
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: plorig
+mail: plorig@example.com
+telephonenumber: +1 408 555 0624
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 1276
+userpassword: calorimeter
+
+dn: uid=ajensen, ou=People, dc=example,dc=com
+cn: Allison Jensen
+sn: Jensen
+givenname: Allison
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: ajensen
+mail: ajensen@example.com
+telephonenumber: +1 408 555 7892
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 0784
+userpassword: coltsfoot
+
+dn: uid=kschmith, ou=People, dc=example,dc=com
+cn: Kelly Schmith
+sn: Schmith
+givenname: Kelly
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: kschmith
+mail: kschmith@example.com
+telephonenumber: +1 408 555 9749
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 2221
+userpassword: purvey
+
+dn: uid=pworrell, ou=People, dc=example,dc=com
+cn: Pete Worrell
+sn: Worrell
+givenname: Pete
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: pworrell
+mail: pworrell@example.com
+telephonenumber: +1 408 555 1637
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 2449
+userpassword: solicitous
+
+dn: uid=mreuter, ou=People, dc=example,dc=com
+cn: Matthew Reuter
+sn: Reuter
+givenname: Matthew
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: mreuter
+mail: mreuter@example.com
+telephonenumber: +1 408 555 6879
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 1356
+userpassword: oblivious
+
+dn: uid=gtyler, ou=People, dc=example,dc=com
+cn: Gern Tyler
+sn: Tyler
+givenname: Gern
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: gtyler
+mail: gtyler@example.com
+telephonenumber: +1 408 555 1020
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0312
+userpassword: typology
+
+dn: uid=tschmith, ou=People, dc=example,dc=com
+cn: Tobias Schmith
+sn: Schmith
+givenname: Tobias
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: tschmith
+mail: tschmith@example.com
+telephonenumber: +1 408 555 9626
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 4607
+userpassword: compost
+
+dn: uid=bjense2, ou=People, dc=example,dc=com
+cn: Bjorn Jensen
+sn: Jensen
+givenname: Bjorn
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: bjense2
+mail: bjense2@example.com
+telephonenumber: +1 408 555 5655
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 4294
+userpassword: mortgage
+
+dn: uid=dswain, ou=People, dc=example,dc=com
+cn: Dietrich Swain
+sn: Swain
+givenname: Dietrich
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Sunnyvale
+uid: dswain
+mail: dswain@example.com
+telephonenumber: +1 408 555 9222
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 4396
+userpassword: freedom
+
+dn: uid=ahall, ou=People, dc=example,dc=com
+cn: Andy Hall
+sn: Hall
+givenname: Andy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: ahall
+mail: ahall@example.com
+telephonenumber: +1 408 555 6169
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 3050
+userpassword: slater
+
+dn: uid=jmuffly, ou=People, dc=example,dc=com
+cn: Jeff Muffly
+sn: Muffly
+givenname: Jeff
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: jmuffly
+mail: jmuffly@example.com
+telephonenumber: +1 408 555 5287
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 0997
+userpassword: dictate
+
+dn: uid=tjensen, ou=People, dc=example,dc=com
+cn: Ted Jensen
+sn: Jensen
+givenname: Ted
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: tjensen
+mail: tjensen@example.com
+telephonenumber: +1 408 555 8622
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 4717
+userpassword: ecosystem
+
+dn: uid=ahunter, ou=People, dc=example,dc=com
+cn: Allison Hunter
+sn: Hunter
+givenname: Allison
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Sunnyvale
+uid: ahunter
+mail: ahunter@example.com
+telephonenumber: +1 408 555 7713
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1213
+userpassword: egregious
+
+dn: uid=jgoldste, ou=People, dc=example,dc=com
+cn: Jon Goldstein
+sn: Goldstein
+givenname: Jon
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: jgoldste
+mail: jgoldste@example.com
+telephonenumber: +1 408 555 5769
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 1454
+userpassword: yellow
+
+dn: uid=aworrell, ou=People, dc=example,dc=com
+cn: Alan Worrell
+sn: Worrell
+givenname: Alan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: aworrell
+mail: aworrell@example.com
+telephonenumber: +1 408 555 1591
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 3966
+userpassword: gargoyle
+
+dn: uid=wlutz, ou=People, dc=example,dc=com
+cn: Wendy Lutz
+sn: Lutz
+givenname: Wendy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: wlutz
+mail: wlutz@example.com
+telephonenumber: +1 408 555 3358
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 4912
+userpassword: bassinet
+
+dn: uid=jlutz, ou=People, dc=example,dc=com
+cn: Janet Lutz
+sn: Lutz
+givenname: Janet
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: jlutz
+mail: jlutz@example.com
+telephonenumber: +1 408 555 4902
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 2544
+userpassword: autumn
+
+dn: uid=dlangdon, ou=People, dc=example,dc=com
+cn: Dan Langdon
+sn: Langdon
+givenname: Dan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: dlangdon
+mail: dlangdon@example.com
+telephonenumber: +1 408 555 7044
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 3263
+userpassword: botulin
+
+dn: uid=aknutson, ou=People, dc=example,dc=com
+cn: Ashley Knutson
+sn: Knutson
+givenname: Ashley
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: aknutson
+mail: aknutson@example.com
+telephonenumber: +1 408 555 2169
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 4736
+userpassword: maltose
+
+dn: uid=kmcinnis, ou=People, dc=example,dc=com
+cn: Kelly Mcinnis
+sn: Mcinnis
+givenname: Kelly
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: kmcinnis
+mail: kmcinnis@example.com
+telephonenumber: +1 408 555 8596
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 4312
+userpassword: stargaze
+
+dn: uid=tcouzens, ou=People, dc=example,dc=com
+cn: Trent Couzens
+sn: Couzens
+givenname: Trent
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: tcouzens
+mail: tcouzens@example.com
+telephonenumber: +1 408 555 8401
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 3994
+userpassword: tambourine
+
+dn: uid=lstockto, ou=People, dc=example,dc=com
+cn: Lee Stockton
+sn: Stockton
+givenname: Lee
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: lstockto
+mail: lstockto@example.com
+telephonenumber: +1 408 555 0518
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0169
+userpassword: brooklyn
+
+dn: uid=jbourke, ou=People, dc=example,dc=com
+cn: Jon Bourke
+sn: Bourke
+givenname: Jon
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: jbourke
+mail: jbourke@example.com
+telephonenumber: +1 408 555 8541
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0034
+userpassword: brainwash
+
+dn: uid=dlanoway, ou=People, dc=example,dc=com
+cn: Dan Lanoway
+sn: Lanoway
+givenname: Dan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: dlanoway
+mail: dlanoway@example.com
+telephonenumber: +1 408 555 2017
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 3540
+userpassword: manhattan
+
+dn: uid=kcope, ou=People, dc=example,dc=com
+cn: Karl Cope
+sn: Cope
+givenname: Karl
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: kcope
+mail: kcope@example.com
+telephonenumber: +1 408 555 2709
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 3040
+userpassword: forfeiture
+
+dn: uid=abarnes, ou=People, dc=example,dc=com
+cn: Anne-Louise Barnes
+sn: Barnes
+givenname: Anne-Louise
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Santa Clara
+uid: abarnes
+mail: abarnes@example.com
+telephonenumber: +1 408 555 9445
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 2290
+userpassword: chevron
+
+dn: uid=rjensen, ou=People, dc=example,dc=com
+cn: Richard Jensen
+sn: Jensen
+givenname: Richard
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: rjensen
+mail: rjensen@example.com
+telephonenumber: +1 408 555 5957
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 2631
+userpassword: disciplinarian
+
+dn: uid=phun2, ou=People, dc=example,dc=com
+cn: Pete Hunt
+sn: Hunt
+givenname: Pete
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: phun2
+mail: phun2@example.com
+telephonenumber: +1 408 555 0342
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 0087
+userpassword: absorb
+
+dn: uid=mvaughan, ou=People, dc=example,dc=com
+cn: Matthew Vaughan
+sn: Vaughan
+givenname: Matthew
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Sunnyvale
+uid: mvaughan
+mail: mvaughan@example.com
+telephonenumber: +1 408 555 4692
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 4508
+userpassword: submitted
+
+dn: uid=jlut2, ou=People, dc=example,dc=com
+cn: James Lutz
+sn: Lutz
+givenname: James
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: jlut2
+mail: jlut2@example.com
+telephonenumber: +1 408 555 9689
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 3541
+userpassword: shrank
+
+dn: uid=mjablons, ou=People, dc=example,dc=com
+cn: Morgan Jablonski
+sn: Jablonski
+givenname: Morgan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: mjablons
+mail: mjablons@example.com
+telephonenumber: +1 408 555 0813
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 3160
+userpassword: minimal
+
+dn: uid=pchassin, ou=People, dc=example,dc=com
+cn: Peter Chassin
+sn: Chassin
+givenname: Peter
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Santa Clara
+uid: pchassin
+mail: pchassin@example.com
+telephonenumber: +1 408 555 2816
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 4524
+userpassword: barbital
+
+dn: uid=dcope, ou=People, dc=example,dc=com
+cn: Dan Cope
+sn: Cope
+givenname: Dan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Sunnyvale
+uid: dcope
+mail: dcope@example.com
+telephonenumber: +1 408 555 9813
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 1737
+userpassword: snifter
+
+dn: uid=jrent2, ou=People, dc=example,dc=com
+cn: Judy Rentz
+sn: Rentz
+givenname: Judy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Santa Clara
+uid: jrent2
+mail: jrent2@example.com
+telephonenumber: +1 408 555 2523
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 4405
+userpassword: tachistoscope
+
+dn: uid=tcruse, ou=People, dc=example,dc=com
+cn: Tobias Cruse
+sn: Cruse
+givenname: Tobias
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: tcruse
+mail: tcruse@example.com
+telephonenumber: +1 408 555 5980
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 4191
+userpassword: flinty
+
+dn: uid=eward, ou=People, dc=example,dc=com
+cn: Eric Ward
+sn: Ward
+givenname: Eric
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: eward
+mail: eward@example.com
+telephonenumber: +1 408 555 2320
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 4874
+userpassword: episcopal
+
+dn: uid=ttully, ou=People, dc=example,dc=com
+cn: Torrey Tully
+sn: Tully
+givenname: Torrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: ttully
+mail: ttully@example.com
+telephonenumber: +1 408 555 2274
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 3924
+userpassword: schooner
+
+dn: uid=charvey, ou=People, dc=example,dc=com
+cn: Cecil Harvey
+sn: Harvey
+givenname: Cecil
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: charvey
+mail: charvey@example.com
+telephonenumber: +1 408 555 1815
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 4583
+userpassword: journalese
+
+dn: uid=rfisher, ou=People, dc=example,dc=com
+cn: Randy Fisher
+sn: Fisher
+givenname: Randy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: rfisher
+mail: rfisher@example.com
+telephonenumber: +1 408 555 1506
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 1579
+userpassword: pomegranate
+
+dn: uid=alangdon, ou=People, dc=example,dc=com
+cn: Andrew Langdon
+sn: Langdon
+givenname: Andrew
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: alangdon
+mail: alangdon@example.com
+telephonenumber: +1 408 555 8289
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 2254
+userpassword: muzzle
+
+dn: uid=drose, ou=People, dc=example,dc=com
+cn: David Rose
+sn: Rose
+givenname: David
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Sunnyvale
+uid: drose
+mail: drose@example.com
+telephonenumber: +1 408 555 3963
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 4012
+userpassword: gubernatorial
+
+dn: uid=polfield, ou=People, dc=example,dc=com
+cn: Peter Olfield
+sn: Olfield
+givenname: Peter
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: polfield
+mail: polfield@example.com
+telephonenumber: +1 408 555 8231
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1376
+userpassword: monologue
+
+dn: uid=awalker, ou=People, dc=example,dc=com
+cn: Andy Walker
+sn: Walker
+givenname: Andy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: awalker
+mail: awalker@example.com
+telephonenumber: +1 408 555 9199
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 0061
+userpassword: detonable
+
+dn: uid=lrentz, ou=People, dc=example,dc=com
+cn: Lex Rentz
+sn: Rentz
+givenname: Lex
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: lrentz
+mail: lrentz@example.com
+telephonenumber: +1 408 555 2019
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 2203
+userpassword: calcium
+
+dn: uid=jvaughan, ou=People, dc=example,dc=com
+cn: Jeff Vaughan
+sn: Vaughan
+givenname: Jeff
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: jvaughan
+mail: jvaughan@example.com
+telephonenumber: +1 408 555 4543
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 1734
+userpassword: appoint
+
+dn: uid=bfrancis, ou=People, dc=example,dc=com
+cn: Barbara Francis
+sn: Francis
+givenname: Barbara
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: bfrancis
+mail: bfrancis@example.com
+telephonenumber: +1 408 555 9111
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 3743
+userpassword: holystone
+
+dn: uid=ewalker, ou=People, dc=example,dc=com
+cn: Eric Walker
+sn: Walker
+givenname: Eric
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Cupertino
+uid: ewalker
+mail: ewalker@example.com
+telephonenumber: +1 408 555 6387
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 2295
+userpassword: beguile
+
+dn: uid=tjames, ou=People, dc=example,dc=com
+cn: Tobias James
+sn: James
+givenname: Tobias
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: tjames
+mail: tjames@example.com
+telephonenumber: +1 408 555 2458
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 0730
+userpassword: turtle
+
+dn: uid=brigden, ou=People, dc=example,dc=com
+cn: Bjorn Rigden
+sn: Rigden
+givenname: Bjorn
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: brigden
+mail: brigden@example.com
+telephonenumber: +1 408 555 5263
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 1643
+userpassword: purple
+
+dn: uid=ecruse, ou=People, dc=example,dc=com
+cn: Eric Cruse
+sn: Cruse
+givenname: Eric
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: ecruse
+mail: ecruse@example.com
+telephonenumber: +1 408 555 0648
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 4233
+userpassword: platelet
+
+dn: uid=rjense2, ou=People, dc=example,dc=com
+cn: Randy Jensen
+sn: Jensen
+givenname: Randy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Sunnyvale
+uid: rjense2
+mail: rjense2@example.com
+telephonenumber: +1 408 555 9045
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 1984
+userpassword: transpose
+
+dn: uid=rhunt, ou=People, dc=example,dc=com
+cn: Richard Hunt
+sn: Hunt
+givenname: Richard
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: rhunt
+mail: rhunt@example.com
+telephonenumber: +1 408 555 0139
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 0718
+userpassword: becloud
+
+dn: uid=bparker, ou=People, dc=example,dc=com
+cn: Barry Parker
+sn: Parker
+givenname: Barry
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Sunnyvale
+uid: bparker
+mail: bparker@example.com
+telephonenumber: +1 408 555 4647
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 1148
+userpassword: lenticular
+
+dn: uid=ealexand, ou=People, dc=example,dc=com
+cn: Erin Alexander
+sn: Alexander
+givenname: Erin
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: ealexand
+mail: ealexand@example.com
+telephonenumber: +1 408 555 5563
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 2434
+userpassword: galactose
+
+dn: uid=mtyler, ou=People, dc=example,dc=com
+cn: Matthew Tyler
+sn: Tyler
+givenname: Matthew
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: mtyler
+mail: mtyler@example.com
+telephonenumber: +1 408 555 7907
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 2701
+userpassword: instantiate
+
+dn: uid=elott, ou=People, dc=example,dc=com
+cn: Emanuel Lott
+sn: Lott
+givenname: Emanuel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: elott
+mail: elott@example.com
+telephonenumber: +1 408 555 0932
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 3906
+userpassword: holdout
+
+dn: uid=cnewport, ou=People, dc=example,dc=com
+cn: Christoph Newport
+sn: Newport
+givenname: Christoph
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Sunnyvale
+uid: cnewport
+mail: cnewport@example.com
+telephonenumber: +1 408 555 0066
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 0056
+userpassword: expertise
+
+dn: uid=jvedder, ou=People, dc=example,dc=com
+cn: Jeff Vedder
+sn: Vedder
+givenname: Jeff
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: jvedder
+mail: jvedder@example.com
+telephonenumber: +1 408 555 4668
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 3445
+userpassword: befitting
+
+dn: cn=Accounting Managers,ou=groups,dc=example,dc=com
+objectclass: top
+objectclass: groupOfUniqueNames
+cn: Accounting Managers
+ou: groups
+uniquemember: uid=scarter, ou=People, dc=example,dc=com
+uniquemember: uid=tmorris, ou=People, dc=example,dc=com
+description: People who can manage accounting entries
+
+dn: cn=HR Managers,ou=groups,dc=example,dc=com
+objectclass: top
+objectclass: groupOfUniqueNames
+cn: HR Managers
+ou: groups
+uniquemember: uid=kvaughan, ou=People, dc=example,dc=com
+uniquemember: uid=cschmith, ou=People, dc=example,dc=com
+description: People who can manage HR entries
+
+dn: cn=QA Managers,ou=groups,dc=example,dc=com
+objectclass: top
+objectclass: groupOfUniqueNames
+cn: QA Managers
+ou: groups
+uniquemember: uid=abergin, ou=People, dc=example,dc=com
+uniquemember: uid=jwalker, ou=People, dc=example,dc=com
+description: People who can manage QA entries
+
+dn: cn=PD Managers,ou=groups,dc=example,dc=com
+objectclass: top
+objectclass: groupOfUniqueNames
+cn: PD Managers
+ou: groups
+uniquemember: uid=kwinters, ou=People, dc=example,dc=com
+uniquemember: uid=trigden, ou=People, dc=example,dc=com
+description: People who can manage engineer entries
+
Added: incubator/directory/eve/branches/start/src/ldif/smallest_example.ldif
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/ldif/smallest_example.ldif Thu Jun 24 00:06:35 2004
@@ -0,0 +1,408 @@
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# dc=domain,dc=com sample LDIF file
+#
+# Notes:
+# 160 total entries.
+# 1 (objectclass=domain) entry (dc=domain,dc=com).
+# 4 (objectclass=organizationalunit) entries.
+# 5 (objectclass=groupofuniquenames) entries.
+# 150 (objectclass=person) entries (all under ou=people,dc=domain,dc=com).
+#
+
+dn: ou=Groups,dc=domain,dc=com
+objectclass: top
+objectclass: organizationalunit
+ou: Groups
+
+dn: cn=Directory Administrators,ou=Groups,dc=domain,dc=com
+cn: Directory Administrators
+objectclass: top
+objectclass: groupofuniquenames
+ou: Groups
+uniquemember: uid=kvaughan,ou=People,dc=domain,dc=com
+uniquemember: uid=rdaugherty,ou=People,dc=domain,dc=com
+uniquemember: uid=hmiller,ou=People,dc=domain,dc=com
+
+dn: ou=People,dc=domain,dc=com
+objectclass: top
+objectclass: organizationalunit
+ou: People
+
+dn: ou=Special Users,dc=domain,dc=com
+objectclass: top
+objectclass: organizationalUnit
+ou: Special Users
+description: Special Administrative Accounts
+
+dn: uid=scarter,ou=People,dc=domain,dc=com
+cn: Sam Carter
+sn: Carter
+givenname: Sam
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: scarter
+mail: scarter@domain.com
+telephonenumber: +1 408 555 4798
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 4612
+userpassword: sprain
+
+dn: uid=tmorris,ou=People,dc=domain,dc=com
+cn: Ted Morris
+sn: Morris
+givenname: Ted
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: tmorris
+mail: tmorris@domain.com
+telephonenumber: +1 408 555 9187
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 4117
+userpassword: irrefutable
+
+dn: uid=kvaughan,ou=People,dc=domain,dc=com
+cn: Kirsten Vaughan
+sn: Vaughan
+givenname: Kirsten
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: kvaughan
+mail: kvaughan@domain.com
+telephonenumber: +1 408 555 5625
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 2871
+userpassword: bribery
+
+dn: uid=abergin,ou=People,dc=domain,dc=com
+cn: Andy Bergin
+sn: Bergin
+givenname: Andy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Cupertino
+uid: abergin
+mail: abergin@domain.com
+telephonenumber: +1 408 555 8585
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 3472
+userpassword: inflict
+
+dn: uid=dmiller,ou=People,dc=domain,dc=com
+cn: David Miller
+sn: Miller
+givenname: David
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: dmiller
+mail: dmiller@domain.com
+telephonenumber: +1 408 555 9423
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 4135
+userpassword: gosling
+
+dn: uid=gfarmer,ou=People,dc=domain,dc=com
+cn: Gern Farmer
+sn: Farmer
+givenname: Gern
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: gfarmer
+mail: gfarmer@domain.com
+telephonenumber: +1 408 555 6201
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1269
+userpassword: ruling
+
+dn: uid=kwinters,ou=People,dc=domain,dc=com
+cn: Kelly Winters
+sn: Winters
+givenname: Kelly
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: kwinters
+mail: kwinters@domain.com
+telephonenumber: +1 408 555 9069
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 4178
+userpassword: forsook
+
+dn: uid=trigden,ou=People,dc=domain,dc=com
+cn: Torrey Rigden
+sn: Rigden
+givenname: Torrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: trigden
+mail: trigden@domain.com
+telephonenumber: +1 408 555 9280
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 3584
+userpassword: sensitive
+
+dn: uid=cschmith,ou=People,dc=domain,dc=com
+cn: Chris Schmith
+sn: Schmith
+givenname: Chris
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: cschmith
+mail: cschmith@domain.com
+telephonenumber: +1 408 555 8011
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0416
+userpassword: hypotenuse
+
+dn: uid=jwallace,ou=People,dc=domain,dc=com
+cn: Judy Wallace
+sn: Wallace
+givenname: Judy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: jwallace
+mail: jwallace@domain.com
+telephonenumber: +1 408 555 0319
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1033
+userpassword: linear
+
+dn: uid=jwalker,ou=People,dc=domain,dc=com
+cn: John Walker
+sn: Walker
+givenname: John
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Cupertino
+uid: jwalker
+mail: jwalker@domain.com
+telephonenumber: +1 408 555 1476
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 3915
+userpassword: dogleg
+
+dn: uid=tclow,ou=People,dc=domain,dc=com
+cn: Torrey Clow
+sn: Clow
+givenname: Torrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: tclow
+mail: tclow@domain.com
+telephonenumber: +1 408 555 8825
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 4376
+userpassword: cardreader
+
+dn: uid=bparker,ou=People,dc=domain,dc=com
+cn: Barry Parker
+sn: Parker
+givenname: Barry
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Sunnyvale
+uid: bparker
+mail: bparker@domain.com
+telephonenumber: +1 408 555 4647
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 1148
+userpassword: lenticular
+
+dn: uid=ealexand,ou=People,dc=domain,dc=com
+cn: Erin Alexander
+sn: Alexander
+givenname: Erin
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: ealexand
+mail: ealexand@domain.com
+telephonenumber: +1 408 555 5563
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 2434
+userpassword: galactose
+
+dn: uid=mtyler,ou=People,dc=domain,dc=com
+cn: Matthew Tyler
+sn: Tyler
+givenname: Matthew
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: mtyler
+mail: mtyler@domain.com
+telephonenumber: +1 408 555 7907
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 2701
+userpassword: instantiate
+
+dn: uid=elott,ou=People,dc=domain,dc=com
+cn: Emanuel Lott
+sn: Lott
+givenname: Emanuel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: elott
+mail: elott@domain.com
+telephonenumber: +1 408 555 0932
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 3906
+userpassword: holdout
+
+dn: uid=cnewport,ou=People,dc=domain,dc=com
+cn: Christoph Newport
+sn: Newport
+givenname: Christoph
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Sunnyvale
+uid: cnewport
+mail: cnewport@domain.com
+telephonenumber: +1 408 555 0066
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 0056
+userpassword: expertise
+
+dn: uid=jvedder,ou=People,dc=domain,dc=com
+cn: Jeff Vedder
+sn: Vedder
+givenname: Jeff
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: jvedder
+mail: jvedder@domain.com
+telephonenumber: +1 408 555 4668
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 3445
+userpassword: befitting
+
+dn: cn=Accounting Managers,ou=Groups,dc=domain,dc=com
+objectclass: top
+objectclass: groupOfUniqueNames
+cn: Accounting Managers
+ou: Groups
+uniquemember: uid=scarter,ou=People,dc=domain,dc=com
+uniquemember: uid=tmorris,ou=People,dc=domain,dc=com
+description: People who can manage accounting entries
+
+dn: cn=HR Managers,ou=Groups,dc=domain,dc=com
+objectclass: top
+objectclass: groupOfUniqueNames
+cn: HR Managers
+ou: Groups
+uniquemember: uid=kvaughan,ou=People,dc=domain,dc=com
+uniquemember: uid=cschmith,ou=People,dc=domain,dc=com
+description: People who can manage HR entries
+
+dn: cn=QA Managers,ou=Groups,dc=domain,dc=com
+objectclass: top
+objectclass: groupOfUniqueNames
+cn: QA Managers
+ou: Groups
+uniquemember: uid=abergin,ou=People,dc=domain,dc=com
+uniquemember: uid=jwalker,ou=People,dc=domain,dc=com
+description: People who can manage QA entries
+
+dn: cn=PD Managers,ou=Groups,dc=domain,dc=com
+objectclass: top
+objectclass: groupOfUniqueNames
+cn: PD Managers
+ou: Groups
+uniquemember: uid=kwinters,ou=People,dc=domain,dc=com
+uniquemember: uid=trigden,ou=People,dc=domain,dc=com
+description: People who can manage engineer entries
+
+dn: ou=Netscape Servers,dc=domain,dc=com
+objectclass: top
+objectclass: organizationalUnit
+ou: Netscape Servers
+description: Standard branch for Netscape Server registration
+
Added: incubator/directory/eve/branches/start/src/schema/corba.schema
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/schema/corba.schema Thu Jun 24 00:06:35 2004
@@ -0,0 +1,222 @@
+# Corba Object Schema
+# $OpenLDAP: pkg/ldap/servers/slapd/schema/corba.schema,v 1.1.2.1 2000/09/13 00:42:36 kurt Exp $
+# depends upon core.schema
+
+# Network Working Group V. Ryan
+# Request for Comments: 2714 R. Lee
+# Category: Informational S. Seligman
+# Sun Microsystems, Inc.
+# October 1999
+#
+#
+# Schema for Representing CORBA Object References in an LDAP Directory
+#
+# Status of this Memo
+#
+# This memo provides information for the Internet community. It does
+# not specify an Internet standard of any kind. Distribution of this
+# memo is unlimited.
+#
+# Copyright Notice
+#
+# Copyright (C) The Internet Society (1999). All Rights Reserved.
+#
+# Abstract
+#
+# CORBA [CORBA] is the Common Object Request Broker Architecture
+# defined by the Object Management Group. This document defines the
+# schema for representing CORBA object references in an LDAP directory
+# [LDAPv3].
+#
+# [trimmed]
+
+# 3. Attribute Type Definitions
+#
+# The following attribute types are defined in this document:
+#
+# corbaIor
+# corbaRepositoryId
+#
+# 3.1 corbaIor
+#
+# This attribute stores the string representation of the interoperable
+# object reference (IOR) for a CORBA object. An IOR is an opaque handle
+# for the object which contains the information necessary to locate the
+# object, even if the object is in another ORB.
+#
+# This attribute's syntax is 'IA5 String' and its case is
+# insignificant.
+#
+# ( 1.3.6.1.4.1.42.2.27.4.1.14
+# NAME 'corbaIor'
+# DESC 'Stringified interoperable object reference of a CORBA object'
+# EQUALITY caseIgnoreIA5Match
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+# SINGLE-VALUE
+# )
+#
+attributetype ( 1.3.6.1.4.1.42.2.27.4.1.14
+ NAME 'corbaIor'
+ DESC 'Stringified interoperable object reference of a CORBA object'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE )
+
+# 3.2 corbaRepositoryId
+#
+# Each CORBA interface has a unique "repository id" (also called "type
+# id") that identifies the interface. A CORBA object has one or more
+# repository ids, one for each interface that it implements.
+#
+# The format of a repository id can be any string, but the OMG
+# specifies four standard formats:
+#
+# a. IDL-style
+#
+# IDL:Prefix/ModuleName/InterfaceName:VersionNumber
+#
+# For example, the repository id for the "NamingContext" in OMG's COS
+# Naming module is: "IDL:omg.org/CosNaming/NamingContext:1.0".
+#
+# b. RMI-style
+#
+# RMI:ClassName:HashCode[:SUID]
+#
+# This format is used by RMI-IIOP remote objects [RMI-IIOP].
+# "ClassName" is the fully qualified name of the class (for example,
+# "java.lang.String"). "HashCode" is the object's hash code (that is,
+# that obtained by invoking the "hashCode()" method). "SUID" is the
+# "stream unique identifier", which is a 64-bit number that uniquely
+# identifies the serialization version of the class; SUID is optional
+# in the repository id.
+#
+# c. DCE-style
+#
+# DCE:UUID
+#
+# This format is used for DCE/CORBA interoperability [CORBA-DCE].
+# "UUID" represents a DCE UUID.
+#
+# d. "local"
+#
+# This format is defined by the local Object Request Broker (ORB).
+#
+# The corbaRepositoryId attribute is a multivalued attribute; each
+# value records a single repository id of an interface implemented by
+# the CORBA object. This attribute need not contain a complete list of
+# the interfaces implemented by the CORBA object.
+#
+# This attribute's syntax is 'Directory String' and its case is
+# significant. The values of this attribute are encoded using UTF-8.
+# Some values may require translation from their native representation
+# in order to be correctly encoded using UTF-8.
+#
+# ( 1.3.6.1.4.1.42.2.27.4.1.15
+# NAME 'corbaRepositoryId'
+# DESC 'Repository ids of interfaces implemented by a CORBA object'
+# EQUALITY caseExactMatch
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+# )
+#
+#
+attributetype ( 1.3.6.1.4.1.42.2.27.4.1.15
+ NAME 'corbaRepositoryId'
+ DESC 'Repository ids of interfaces implemented by a CORBA object'
+ EQUALITY caseExactMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+# 4. Object Class Definitions
+#
+# The following object classes are defined in this document:
+#
+# corbaContainer
+# corbaObject
+# corbaObjectReference
+#
+# 4.1 corbaContainer
+#
+# This structural object class represents a container for a CORBA
+# object.
+#
+# ( 1.3.6.1.4.1.42.2.27.4.2.10
+# NAME 'corbaContainer'
+# DESC 'Container for a CORBA object'
+# SUP top
+# STRUCTURAL
+# MUST ( cn )
+# )
+#
+objectclass ( 1.3.6.1.4.1.42.2.27.4.2.10
+ NAME 'corbaContainer'
+ DESC 'Container for a CORBA object'
+ SUP top
+ STRUCTURAL
+ MUST cn )
+
+# 4.2 corbaObject
+#
+# This abstract object class is the root class for representing a CORBA
+# object.
+#
+# ( 1.3.6.1.4.1.42.2.27.4.2.9
+# NAME 'corbaObject'
+# DESC 'CORBA object representation'
+# SUP top
+# ABSTRACT
+# MAY ( corbaRepositoryId $ description )
+# )
+#
+objectclass ( 1.3.6.1.4.1.42.2.27.4.2.9
+ NAME 'corbaObject'
+ DESC 'CORBA object representation'
+ SUP top
+ ABSTRACT
+ MAY ( corbaRepositoryId $ description ) )
+
+# 4.3 corbaObjectReference
+#
+# This auxiliary object class represents a CORBA object reference. It
+# must be mixed in with a structural object class.
+#
+# ( 1.3.6.1.4.1.42.2.27.4.2.11
+# NAME 'corbaObjectReference'
+# DESC 'CORBA interoperable object reference'
+# SUP corbaObject
+# AUXILIARY
+# MUST ( corbaIor )
+# )
+#
+objectclass ( 1.3.6.1.4.1.42.2.27.4.2.11
+ NAME 'corbaObjectReference'
+ DESC 'CORBA interoperable object reference'
+ SUP corbaObject
+ AUXILIARY
+ MUST corbaIor )
+
+# 10. Full Copyright Statement
+#
+# Copyright (C) The Internet Society (1999). All Rights Reserved.
+#
+# This document and translations of it may be copied and furnished to
+# others, and derivative works that comment on or otherwise explain it
+# or assist in its implementation may be prepared, copied, published
+# and distributed, in whole or in part, without restriction of any
+# kind, provided that the above copyright notice and this paragraph are
+# included on all such copies and derivative works. However, this
+# document itself may not be modified in any way, such as by removing
+# the copyright notice or references to the Internet Society or other
+# Internet organizations, except as needed for the purpose of
+# developing Internet standards in which case the procedures for
+# copyrights defined in the Internet Standards process must be
+# followed, or as required to translate it into languages other than
+# English.
+#
+# The limited permissions granted above are perpetual and will not be
+# revoked by the Internet Society or its successors or assigns.
+#
+# This document and the information contained herein is provided on an
+# "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+# TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+# BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+# HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
Added: incubator/directory/eve/branches/start/src/schema/core.schema
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/schema/core.schema Thu Jun 24 00:06:35 2004
@@ -0,0 +1,606 @@
+# $OpenLDAP: pkg/ldap/servers/slapd/schema/core.schema,v 1.7.2.18 2002/02/08 17:38:54 kurt Exp $
+#
+# OpenLDAP Core schema
+#
+# Includes LDAPv3 schema items from:
+# RFC2251-RFC2256 (LDAPv3)
+#
+# select standard track schema items:
+# RFC2079 (URI)
+# RFC1274 (uid/dc)
+# RFC2247 (dc/dcObject)
+# RFC2589 (Dynamic Directory Services)
+#
+# select informational schema items:
+# RFC2377 (uidObject)
+#
+# select IETF ''work in progress'' LDAPext/LDUP items
+# ldapSubentry
+# ldapRootDSE
+# named referrals
+# alias draft
+
+# Standard X.501(93) Operational Attribute Types from RFC2252
+
+attributetype ( 2.5.18.1 NAME 'createTimestamp'
+ EQUALITY generalizedTimeMatch
+ ORDERING generalizedTimeOrderingMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
+ SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )
+
+attributetype ( 2.5.18.2 NAME 'modifyTimestamp'
+ EQUALITY generalizedTimeMatch
+ ORDERING generalizedTimeOrderingMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
+ SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )
+
+attributetype ( 2.5.18.3 NAME 'creatorsName'
+ EQUALITY distinguishedNameMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
+ SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )
+
+attributetype ( 2.5.18.4 NAME 'modifiersName'
+ EQUALITY distinguishedNameMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
+ SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )
+
+attributetype ( 2.5.18.10 NAME 'subschemaSubentry'
+ EQUALITY distinguishedNameMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 NO-USER-MODIFICATION
+ SINGLE-VALUE USAGE directoryOperation )
+
+attributetype ( 2.5.21.1 NAME 'dITStructureRules'
+ EQUALITY integerFirstComponentMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.17 USAGE directoryOperation )
+
+attributetype ( 2.5.21.2 NAME 'dITContentRules'
+ EQUALITY objectIdentifierFirstComponentMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.16 USAGE directoryOperation )
+
+attributetype ( 2.5.21.4 NAME 'matchingRules'
+ EQUALITY objectIdentifierFirstComponentMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.30 USAGE directoryOperation )
+
+attributetype ( 2.5.21.5 NAME 'attributeTypes'
+ EQUALITY objectIdentifierFirstComponentMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.3 USAGE directoryOperation )
+
+attributetype ( 2.5.21.6 NAME 'objectClasses'
+ EQUALITY objectIdentifierFirstComponentMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.37 USAGE directoryOperation )
+
+attributetype ( 2.5.21.7 NAME 'nameForms'
+ EQUALITY objectIdentifierFirstComponentMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.35 USAGE directoryOperation )
+
+attributetype ( 2.5.21.8 NAME 'matchingRuleUse'
+ EQUALITY objectIdentifierFirstComponentMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.31 USAGE directoryOperation )
+
+# From X.500(93)
+attributetype ( 2.5.21.9 NAME 'structuralObjectClass'
+ DESC 'X.500(93) structural object class'
+ EQUALITY objectIdentifierMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.38
+ NO-USER-MODIFICATION SINGLE-VALUE USAGE directoryOperation )
+
+# LDAP Operational Attributes from RFC2252
+attributetype ( 1.3.6.1.4.1.1466.101.120.5 NAME 'namingContexts'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 USAGE dSAOperation )
+
+attributetype ( 1.3.6.1.4.1.1466.101.120.6 NAME 'altServer'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 USAGE dSAOperation )
+
+attributetype ( 1.3.6.1.4.1.1466.101.120.7 NAME 'supportedExtension'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 USAGE dSAOperation )
+
+attributetype ( 1.3.6.1.4.1.1466.101.120.13 NAME 'supportedControl'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 USAGE dSAOperation )
+
+attributetype ( 1.3.6.1.4.1.1466.101.120.14 NAME 'supportedSASLMechanisms'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE dSAOperation )
+
+attributetype ( 1.3.6.1.4.1.1466.101.120.15 NAME 'supportedLDAPVersion'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 USAGE dSAOperation )
+
+attributetype ( 1.3.6.1.4.1.1466.101.120.16 NAME 'ldapSyntaxes'
+ EQUALITY objectIdentifierFirstComponentMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.54 USAGE directoryOperation )
+
+# Object Classes from RFC2252
+objectclass ( 2.5.20.1 NAME 'subschema' AUXILIARY
+ DESC 'RFC2252: controlling subschema'
+ MAY ( dITStructureRules $ nameForms $ ditContentRules $
+ objectClasses $ attributeTypes $ matchingRules $
+ matchingRuleUse ) )
+
+# Standard attribute types used for subtyping from RFC2256
+
+attributetype ( 2.5.4.41 NAME 'name'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} )
+
+attributetype ( 2.5.4.49 NAME 'distinguishedName'
+ EQUALITY distinguishedNameMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )
+
+# Standard attribute types from RFC2256
+
+attributetype ( 2.5.4.0 NAME 'objectClass'
+ EQUALITY objectIdentifierMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )
+
+attributetype ( 2.5.4.1 NAME 'aliasedObjectName'
+ EQUALITY distinguishedNameMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE )
+
+# obsolete
+attributetype ( 2.5.4.2 NAME 'knowledgeInformation'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} )
+
+attributetype ( 2.5.4.3 NAME ( 'cn' 'commonName' ) SUP name )
+
+attributetype ( 2.5.4.4 NAME ( 'sn' 'surname' ) SUP name )
+
+attributetype ( 2.5.4.5 NAME 'serialNumber' EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.44{64} )
+
+# (2-letter code from ISO 3166)
+attributetype ( 2.5.4.6 NAME ( 'c' 'countryName' ) SUP name SINGLE-VALUE )
+
+attributetype ( 2.5.4.7 NAME ( 'l' 'localityName' ) SUP name )
+
+attributetype ( 2.5.4.8 NAME ( 'st' 'stateOrProvinceName' ) SUP name )
+
+attributetype ( 2.5.4.9 NAME ( 'street' 'streetAddress' )
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
+
+attributetype ( 2.5.4.10 NAME ( 'o' 'organizationName' ) SUP name )
+
+attributetype ( 2.5.4.11 NAME ( 'ou' 'organizationalUnitName' ) SUP name )
+
+attributetype ( 2.5.4.12 NAME 'title' SUP name )
+
+attributetype ( 2.5.4.13 NAME 'description'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} )
+
+# Obsoleted by enhancedSearchGuide
+attributetype ( 2.5.4.14 NAME 'searchGuide'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.25 )
+
+attributetype ( 2.5.4.15 NAME 'businessCategory'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
+
+attributetype ( 2.5.4.16 NAME 'postalAddress'
+ EQUALITY caseIgnoreListMatch
+ SUBSTR caseIgnoreListSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )
+
+attributetype ( 2.5.4.17 NAME 'postalCode'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{40} )
+
+attributetype ( 2.5.4.18 NAME 'postOfficeBox'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{40} )
+
+attributetype ( 2.5.4.19 NAME 'physicalDeliveryOfficeName'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
+
+attributetype ( 2.5.4.20 NAME 'telephoneNumber'
+ EQUALITY telephoneNumberMatch
+ SUBSTR telephoneNumberSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.50{32} )
+
+attributetype ( 2.5.4.21 NAME 'telexNumber'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.52 )
+
+attributetype ( 2.5.4.22 NAME 'teletexTerminalIdentifier'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.51 )
+
+attributetype ( 2.5.4.23 NAME ( 'facsimileTelephoneNumber' 'fax' )
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.22 )
+
+attributetype ( 2.5.4.24 NAME 'x121Address'
+ EQUALITY numericStringMatch
+ SUBSTR numericStringSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.36{15} )
+
+attributetype ( 2.5.4.25 NAME 'internationaliSDNNumber'
+ EQUALITY numericStringMatch
+ SUBSTR numericStringSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.36{16} )
+
+attributetype ( 2.5.4.26 NAME 'registeredAddress' SUP postalAddress
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )
+
+attributetype ( 2.5.4.27 NAME 'destinationIndicator'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.44{128} )
+
+attributetype ( 2.5.4.28 NAME 'preferredDeliveryMethod'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.14
+ SINGLE-VALUE )
+
+attributetype ( 2.5.4.29 NAME 'presentationAddress'
+ EQUALITY presentationAddressMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.43
+ SINGLE-VALUE )
+
+attributetype ( 2.5.4.30 NAME 'supportedApplicationContext'
+ EQUALITY objectIdentifierMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )
+
+attributetype ( 2.5.4.31 NAME 'member' SUP distinguishedName )
+
+attributetype ( 2.5.4.32 NAME 'owner' SUP distinguishedName )
+
+attributetype ( 2.5.4.33 NAME 'roleOccupant' SUP distinguishedName )
+
+attributetype ( 2.5.4.34 NAME 'seeAlso' SUP distinguishedName )
+
+attributetype ( 2.5.4.35 NAME 'userPassword'
+ EQUALITY octetStringMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.40{128} )
+
+# Must be transferred using ;binary
+attributetype ( 2.5.4.36 NAME 'userCertificate'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 )
+
+# Must be transferred using ;binary
+attributetype ( 2.5.4.37 NAME 'cACertificate'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 )
+
+# Must be transferred using ;binary
+attributetype ( 2.5.4.38 NAME 'authorityRevocationList'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.9 )
+
+# Must be transferred using ;binary
+attributetype ( 2.5.4.39 NAME 'certificateRevocationList'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.9 )
+
+# Must be stored and requested in the binary form
+attributetype ( 2.5.4.40 NAME 'crossCertificatePair'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.10 )
+
+# 2.5.4.41 is defined above as it's used for subtyping
+#attributetype ( 2.5.4.41 NAME 'name'
+# EQUALITY caseIgnoreMatch
+# SUBSTR caseIgnoreSubstringsMatch
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} )
+
+attributetype ( 2.5.4.42 NAME ( 'givenName' 'gn' ) SUP name )
+
+attributetype ( 2.5.4.43 NAME 'initials' SUP name
+ DESC 'The initials attribute type contains the initials of some
+ or all of an individuals names, but not the surname(s).' )
+
+attributetype ( 2.5.4.44 NAME 'generationQualifier'
+ DESC 'e.g. Jr or II.'
+ SUP name )
+
+attributetype ( 2.5.4.45 NAME 'x500UniqueIdentifier'
+ EQUALITY bitStringMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )
+
+attributetype ( 2.5.4.46 NAME 'dnQualifier'
+ EQUALITY caseIgnoreMatch
+ ORDERING caseIgnoreOrderingMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 )
+
+attributetype ( 2.5.4.47 NAME 'enhancedSearchGuide'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.21 )
+
+attributetype ( 2.5.4.48 NAME 'protocolInformation'
+ EQUALITY protocolInformationMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )
+
+# 2.5.4.49 is defined above as it's used for subtyping
+#attributetype ( 2.5.4.49 NAME 'distinguishedName'
+# EQUALITY distinguishedNameMatch
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )
+
+attributetype ( 2.5.4.50 NAME 'uniqueMember'
+ EQUALITY uniqueMemberMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )
+
+attributetype ( 2.5.4.51 NAME 'houseIdentifier'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} )
+
+# Must be transferred using ;binary
+attributetype ( 2.5.4.52 NAME 'supportedAlgorithms'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.49 )
+
+# Must be transferred using ;binary
+attributetype ( 2.5.4.53 NAME 'deltaRevocationList'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.9 )
+
+attributetype ( 2.5.4.54 NAME 'dmdName' SUP name )
+
+# Standard object classes from RFC2256
+
+objectclass ( 2.5.6.0 NAME 'top' ABSTRACT
+ MUST objectClass )
+
+objectclass ( 2.5.6.1 NAME 'alias' SUP top STRUCTURAL
+ MUST aliasedObjectName )
+
+objectclass ( 2.5.6.2 NAME 'country' SUP top STRUCTURAL
+ MUST c
+ MAY ( searchGuide $ description ) )
+
+objectclass ( 2.5.6.3 NAME 'locality' SUP top STRUCTURAL
+ MAY ( street $ seeAlso $ searchGuide $ st $ l $ description ) )
+
+objectclass ( 2.5.6.4 NAME 'organization' SUP top STRUCTURAL
+ MUST o
+ MAY ( userPassword $ searchGuide $ seeAlso $ businessCategory $
+ x121Address $ registeredAddress $ destinationIndicator $
+ preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
+ telephoneNumber $ internationaliSDNNumber $
+ facsimileTelephoneNumber $ street $ postOfficeBox $ postalCode $
+ postalAddress $ physicalDeliveryOfficeName $ st $ l $ description ) )
+
+objectclass ( 2.5.6.5 NAME 'organizationalUnit' SUP top STRUCTURAL
+ MUST ou
+ MAY ( userPassword $ searchGuide $ seeAlso $ businessCategory $
+ x121Address $ registeredAddress $ destinationIndicator $
+ preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
+ telephoneNumber $ internationaliSDNNumber $
+ facsimileTelephoneNumber $ street $ postOfficeBox $ postalCode $
+ postalAddress $ physicalDeliveryOfficeName $ st $ l $ description ) )
+
+objectclass ( 2.5.6.6 NAME 'person' SUP top STRUCTURAL
+ MUST ( sn $ cn )
+ MAY ( userPassword $ telephoneNumber $ seeAlso $ description ) )
+
+objectclass ( 2.5.6.7 NAME 'organizationalPerson' SUP person STRUCTURAL
+ MAY ( title $ x121Address $ registeredAddress $ destinationIndicator $
+ preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
+ telephoneNumber $ internationaliSDNNumber $
+ facsimileTelephoneNumber $ street $ postOfficeBox $ postalCode $
+ postalAddress $ physicalDeliveryOfficeName $ ou $ st $ l ) )
+
+objectclass ( 2.5.6.8 NAME 'organizationalRole' SUP top STRUCTURAL
+ MUST cn
+ MAY ( x121Address $ registeredAddress $ destinationIndicator $
+ preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
+ telephoneNumber $ internationaliSDNNumber $ facsimileTelephoneNumber $
+ seeAlso $ roleOccupant $ preferredDeliveryMethod $ street $
+ postOfficeBox $ postalCode $ postalAddress $
+ physicalDeliveryOfficeName $ ou $ st $ l $ description ) )
+
+objectclass ( 2.5.6.9 NAME 'groupOfNames' SUP top STRUCTURAL
+ MUST ( member $ cn )
+ MAY ( businessCategory $ seeAlso $ owner $ ou $ o $ description ) )
+
+objectclass ( 2.5.6.10 NAME 'residentialPerson' SUP person STRUCTURAL
+ MUST l
+ MAY ( businessCategory $ x121Address $ registeredAddress $
+ destinationIndicator $ preferredDeliveryMethod $ telexNumber $
+ teletexTerminalIdentifier $ telephoneNumber $ internationaliSDNNumber $
+ facsimileTelephoneNumber $ preferredDeliveryMethod $ street $
+ postOfficeBox $ postalCode $ postalAddress $
+ physicalDeliveryOfficeName $ st $ l ) )
+
+objectclass ( 2.5.6.11 NAME 'applicationProcess' SUP top STRUCTURAL
+ MUST cn
+ MAY ( seeAlso $ ou $ l $ description ) )
+
+objectclass ( 2.5.6.12 NAME 'applicationEntity' SUP top STRUCTURAL
+ MUST ( presentationAddress $ cn )
+ MAY ( supportedApplicationContext $ seeAlso $ ou $ o $ l $
+ description ) )
+
+objectclass ( 2.5.6.13 NAME 'dSA' SUP applicationEntity STRUCTURAL
+ MAY knowledgeInformation )
+
+objectclass ( 2.5.6.14 NAME 'device' SUP top STRUCTURAL
+ MUST cn
+ MAY ( serialNumber $ seeAlso $ owner $ ou $ o $ l $ description ) )
+
+objectclass ( 2.5.6.15 NAME 'strongAuthenticationUser' SUP top AUXILIARY
+ MUST userCertificate )
+
+objectclass ( 2.5.6.16 NAME 'certificationAuthority' SUP top AUXILIARY
+ MUST ( authorityRevocationList $ certificateRevocationList $
+ cACertificate ) MAY crossCertificatePair )
+
+objectclass ( 2.5.6.17 NAME 'groupOfUniqueNames' SUP top STRUCTURAL
+ MUST ( uniqueMember $ cn )
+ MAY ( businessCategory $ seeAlso $ owner $ ou $ o $ description ) )
+
+objectclass ( 2.5.6.18 NAME 'userSecurityInformation' SUP top AUXILIARY
+ MAY ( supportedAlgorithms ) )
+
+objectclass ( 2.5.6.16.2 NAME 'certificationAuthority-V2' SUP
+ certificationAuthority
+ AUXILIARY MAY ( deltaRevocationList ) )
+
+objectclass ( 2.5.6.19 NAME 'cRLDistributionPoint' SUP top STRUCTURAL
+ MUST ( cn )
+ MAY ( certificateRevocationList $ authorityRevocationList $
+ deltaRevocationList ) )
+
+objectclass ( 2.5.6.20 NAME 'dmd' SUP top STRUCTURAL
+ MUST ( dmdName )
+ MAY ( userPassword $ searchGuide $ seeAlso $ businessCategory $
+ x121Address $ registeredAddress $ destinationIndicator $
+ preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
+ telephoneNumber $ internationaliSDNNumber $ facsimileTelephoneNumber $
+ street $ postOfficeBox $ postalCode $ postalAddress $
+ physicalDeliveryOfficeName $ st $ l $ description ) )
+
+objectclass ( 1.3.6.1.4.1.1466.101.120.111 NAME 'extensibleObject'
+ DESC 'RFC2252: extensible object'
+ SUP top AUXILIARY )
+
+#
+# Standard Track URI label schema from RFC2079
+#
+attributetype ( 1.3.6.1.4.1.250.1.57 NAME 'labeledURI'
+ DESC 'RFC2079: Uniform Resource Identifier with optional label'
+ EQUALITY caseExactMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+objectclass ( 1.3.6.1.4.1.250.3.15 NAME 'labeledURIObject'
+ DESC 'RFC2079: object that contains the URI attribute type'
+ MAY ( labeledURI )
+ SUP top AUXILIARY )
+
+#
+# Standard Track Dynamic Directory Services from RFC2589
+#
+objectclass ( 1.3.6.1.4.1.1466.101.119.2 NAME 'dynamicObject'
+ DESC 'RFC2589: Dynamic Object'
+ SUP top AUXILIARY )
+
+attributetype ( 1.3.6.1.4.1.1466.101.119.3 NAME 'entryTtl'
+ DESC 'RFC2589: entry time-to-live'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE
+ NO-USER-MODIFICATION USAGE dSAOperation )
+
+attributetype ( 1.3.6.1.4.1.1466.101.119.4 NAME 'dynamicSubtrees'
+ DESC 'RFC2589: dynamic subtrees'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 NO-USER-MODIFICATION
+ USAGE dSAOperation )
+
+#
+# Derived from RFC1274, but with new "short names"
+#
+attributetype ( 0.9.2342.19200300.100.1.1
+ NAME ( 'uid' 'userid' )
+ DESC 'RFC1274: user identifier'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+
+attributetype ( 0.9.2342.19200300.100.1.3
+ NAME ( 'mail' 'rfc822Mailbox' )
+ DESC 'RFC1274: RFC822 Mailbox'
+ EQUALITY caseIgnoreIA5Match
+ SUBSTR caseIgnoreIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
+
+objectclass ( 0.9.2342.19200300.100.4.19 NAME 'simpleSecurityObject'
+ DESC 'RFC1274: simple security object'
+ SUP top AUXILIARY
+ MUST userPassword )
+
+# RFC1274 + RFC2247
+attributetype ( 0.9.2342.19200300.100.1.25
+ NAME ( 'dc' 'domainComponent' )
+ DESC 'RFC1274/2247: domain component'
+ EQUALITY caseIgnoreIA5Match
+ SUBSTR caseIgnoreIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+
+# RFC2247
+objectclass ( 1.3.6.1.4.1.1466.344 NAME 'dcObject'
+ DESC 'RFC2247: domain component object'
+ SUP top AUXILIARY MUST dc )
+
+
+# From RFC2377
+objectclass ( 1.3.6.1.1.3.1 NAME 'uidObject'
+ DESC 'RFC2377: uid object'
+ SUP top AUXILIARY MUST uid )
+
+#
+# From draft-zeilenga-ldap-nameref-xx.txt
+# used to represent referrals in the directory
+#
+attributetype ( 2.16.840.1.113730.3.1.34 NAME 'ref'
+ DESC 'Named referral'
+ EQUALITY caseExactMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+ USAGE distributedOperation )
+
+objectclass ( 2.16.840.1.113730.3.2.6 NAME 'referral'
+ DESC 'Named referral object'
+ SUP top STRUCTURAL MUST ref )
+
+#
+# LDAPsubEntry
+# deprecated!
+objectclass ( 2.16.840.1.113719.2.142.6.1.1
+ NAME 'LDAPsubEntry'
+ DESC 'LDAP Subentry'
+ SUP top STRUCTURAL MAY cn )
+
+#
+# OpenLDAProotDSE
+# likely to change!
+objectclass ( 1.3.6.1.4.1.4203.1.4.1
+ NAME ( 'OpenLDAProotDSE' 'LDAProotDSE' )
+ DESC 'OpenLDAP Root DSE object'
+ SUP top STRUCTURAL MAY cn )
+
+#
+# From Cosine Pilot
+#
+attributetype ( 0.9.2342.19200300.100.1.37 NAME 'associatedDomain'
+ EQUALITY caseIgnoreIA5Match
+ SUBSTR caseIgnoreIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+#
+# From U-Mich
+#
+attributetype ( 1.3.6.1.4.1.250.1.32
+ NAME ( 'krbName' 'kerberosName' )
+ DESC 'Kerberos Name'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE )
+
+#
+# draft-zeilenga-ldap-features-xx.txt (supportedFeatures)
+#
+attributetype ( 1.3.6.1.4.1.4203.1.3.5
+ NAME 'supportedFeatures'
+ DESC 'features supported by the server'
+ EQUALITY objectIdentifierMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.38
+ USAGE dSAOperation )
+
+#
+# OpenLDAP specific schema items
+#
+attributetype ( 1.3.6.1.4.1.4203.1.3.1
+ NAME 'entry'
+ DESC 'OpenLDAP ACL entry pseudo-attribute'
+ SYNTAX 1.3.6.1.4.1.4203.1.1.1
+ SINGLE-VALUE NO-USER-MODIFICATION USAGE dSAOperation )
+
+attributetype ( 1.3.6.1.4.1.4203.1.3.2
+ NAME 'children'
+ DESC 'OpenLDAP ACL children pseudo-attribute'
+ SYNTAX 1.3.6.1.4.1.4203.1.1.1
+ SINGLE-VALUE NO-USER-MODIFICATION USAGE dSAOperation )
+
+# Experimental ( subject to change )
+# this really shouldn't be published!
+attributetype ( 1.3.6.1.4.1.4203.666.1.5
+ NAME 'OpenLDAPaci'
+ DESC 'OpenLDAP access control information'
+ EQUALITY OpenLDAPaciMatch
+ SYNTAX 1.3.6.1.4.1.4203.666.2.1
+ USAGE directoryOperation )
Added: incubator/directory/eve/branches/start/src/schema/core.xml
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/schema/core.xml Thu Jun 24 00:06:35 2004
@@ -0,0 +1,1447 @@
+<configuration>
+ <attributetype>
+ <oid>2.5.18.1</oid>
+ <name>
+ <name>'createTimestamp'</name>
+ </name>
+ <equality>generalizedTimeMatch</equality>
+ <ordering>generalizedTimeOrderingMatch</ordering>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.24</syntax>
+ <single-value>true</single-value>
+ <no-user-modification>true</no-user-modification>
+ <usage>directoryOperation</usage>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.18.2</oid>
+ <name>
+ <name>'modifyTimestamp'</name>
+ </name>
+ <equality>generalizedTimeMatch</equality>
+ <ordering>generalizedTimeOrderingMatch</ordering>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.24</syntax>
+ <single-value>true</single-value>
+ <no-user-modification>true</no-user-modification>
+ <usage>directoryOperation</usage>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.18.3</oid>
+ <name>
+ <name>'creatorsName'</name>
+ </name>
+ <equality>distinguishedNameMatch</equality>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.12</syntax>
+ <single-value>true</single-value>
+ <no-user-modification>true</no-user-modification>
+ <usage>directoryOperation</usage>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.18.4</oid>
+ <name>
+ <name>'modifiersName'</name>
+ </name>
+ <equality>distinguishedNameMatch</equality>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.12</syntax>
+ <single-value>true</single-value>
+ <no-user-modification>true</no-user-modification>
+ <usage>directoryOperation</usage>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.18.10</oid>
+ <name>
+ <name>'subschemaSubentry'</name>
+ </name>
+ <equality>distinguishedNameMatch</equality>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.12</syntax>
+ <no-user-modification>true</no-user-modification>
+ <single-value>true</single-value>
+ <usage>directoryOperation</usage>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.21.1</oid>
+ <name>
+ <name>'dITStructureRules'</name>
+ </name>
+ <equality>integerFirstComponentMatch</equality>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.17</syntax>
+ <usage>directoryOperation</usage>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.21.2</oid>
+ <name>
+ <name>'dITContentRules'</name>
+ </name>
+ <equality>objectIdentifierFirstComponentMatch</equality>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.16</syntax>
+ <usage>directoryOperation</usage>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.21.4</oid>
+ <name>
+ <name>'matchingRules'</name>
+ </name>
+ <equality>objectIdentifierFirstComponentMatch</equality>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.30</syntax>
+ <usage>directoryOperation</usage>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.21.5</oid>
+ <name>
+ <name>'attributeTypes'</name>
+ </name>
+ <equality>objectIdentifierFirstComponentMatch</equality>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.3</syntax>
+ <usage>directoryOperation</usage>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.21.6</oid>
+ <name>
+ <name>'objectClasses'</name>
+ </name>
+ <equality>objectIdentifierFirstComponentMatch</equality>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.37</syntax>
+ <usage>directoryOperation</usage>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.21.7</oid>
+ <name>
+ <name>'nameForms'</name>
+ </name>
+ <equality>objectIdentifierFirstComponentMatch</equality>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.35</syntax>
+ <usage>directoryOperation</usage>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.21.8</oid>
+ <name>
+ <name>'matchingRuleUse'</name>
+ </name>
+ <equality>objectIdentifierFirstComponentMatch</equality>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.31</syntax>
+ <usage>directoryOperation</usage>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.21.9</oid>
+ <name>
+ <name>'structuralObjectClass'</name>
+ </name>
+ <desc>'X.500(93) structural object class'</desc>
+ <equality>objectIdentifierMatch</equality>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.38</syntax>
+ <no-user-modification>true</no-user-modification>
+ <single-value>true</single-value>
+ <usage>directoryOperation</usage>
+ </attributetype>
+
+ <attributetype>
+ <oid>1.3.6.1.4.1.1466.101.120.5</oid>
+ <name>
+ <name>'namingContexts'</name>
+ </name>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.12</syntax>
+ <usage>dSAOperation</usage>
+ </attributetype>
+
+ <attributetype>
+ <oid>1.3.6.1.4.1.1466.101.120.6</oid>
+ <name>
+ <name>'altServer'</name>
+ </name>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.26</syntax>
+ <usage>dSAOperation</usage>
+ </attributetype>
+
+ <attributetype>
+ <oid>1.3.6.1.4.1.1466.101.120.7</oid>
+ <name>
+ <name>'supportedExtension'</name>
+ </name>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.38</syntax>
+ <usage>dSAOperation</usage>
+ </attributetype>
+
+ <attributetype>
+ <oid>1.3.6.1.4.1.1466.101.120.13</oid>
+ <name>
+ <name>'supportedControl'</name>
+ </name>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.38</syntax>
+ <usage>dSAOperation</usage>
+ </attributetype>
+
+ <attributetype>
+ <oid>1.3.6.1.4.1.1466.101.120.14</oid>
+ <name>
+ <name>'supportedSASLMechanisms'</name>
+ </name>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.15</syntax>
+ <usage>dSAOperation</usage>
+ </attributetype>
+
+ <attributetype>
+ <oid>1.3.6.1.4.1.1466.101.120.15</oid>
+ <name>
+ <name>'supportedLDAPVersion'</name>
+ </name>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.27</syntax>
+ <usage>dSAOperation</usage>
+ </attributetype>
+
+ <attributetype>
+ <oid>1.3.6.1.4.1.1466.101.120.16</oid>
+ <name>
+ <name>'ldapSyntaxes'</name>
+ </name>
+ <equality>objectIdentifierFirstComponentMatch</equality>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.54</syntax>
+ <usage>directoryOperation</usage>
+ </attributetype>
+
+ <objectclass>
+ <id>2.5.20.1</id>
+ <name>
+ <name>'subschema'</name>
+ </name>
+ <auxiliary>true</auxiliary>
+ <desc>'RFC2252: controlling subschema'</desc>
+ <may>
+ <value>dITStructureRules</value>
+ <value>nameForms</value>
+ <value>ditContentRules</value>
+ <value>objectClasses</value>
+ <value>attributeTypes</value>
+ <value>matchingRules</value>
+ <value>matchingRuleUse</value>
+ </may>
+ </objectclass>
+
+ <attributetype>
+ <oid>2.5.4.41</oid>
+ <name>
+ <name>'name'</name>
+ </name>
+ <equality>caseIgnoreMatch</equality>
+ <substr>caseIgnoreSubstringsMatch</substr>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.15{32768}</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.49</oid>
+ <name>
+ <name>'distinguishedName'</name>
+ </name>
+ <equality>distinguishedNameMatch</equality>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.12</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.0</oid>
+ <name>
+ <name>'objectClass'</name>
+ </name>
+ <equality>objectIdentifierMatch</equality>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.38</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.1</oid>
+ <name>
+ <name>'aliasedObjectName'</name>
+ </name>
+ <equality>distinguishedNameMatch</equality>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.12</syntax>
+ <single-value>true</single-value>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.2</oid>
+ <name>
+ <name>'knowledgeInformation'</name>
+ </name>
+ <equality>caseIgnoreMatch</equality>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.15{32768}</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.3</oid>
+ <name>
+ <name>'cn'</name>
+ <name>'commonName'</name>
+ </name>
+ <sup>name</sup>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.4</oid>
+ <name>
+ <name>'sn'</name>
+ <name>'surname'</name>
+ </name>
+ <sup>name</sup>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.5</oid>
+ <name>
+ <name>'serialNumber'</name>
+ </name>
+ <equality>caseIgnoreMatch</equality>
+ <substr>caseIgnoreSubstringsMatch</substr>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.44{64}</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.6</oid>
+ <name>
+ <name>'c'</name>
+ <name>'countryName'</name>
+ </name>
+ <sup>name</sup>
+ <single-value>true</single-value>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.7</oid>
+ <name>
+ <name>'l'</name>
+ <name>'localityName'</name>
+ </name>
+ <sup>name</sup>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.8</oid>
+ <name>
+ <name>'st'</name>
+ <name>'stateOrProvinceName'</name>
+ </name>
+ <sup>name</sup>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.9</oid>
+ <name>
+ <name>'street'</name>
+ <name>'streetAddress'</name>
+ </name>
+ <equality>caseIgnoreMatch</equality>
+ <substr>caseIgnoreSubstringsMatch</substr>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.15{128}</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.10</oid>
+ <name>
+ <name>'o'</name>
+ <name>'organizationName'</name>
+ </name>
+ <sup>name</sup>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.11</oid>
+ <name>
+ <name>'ou'</name>
+ <name>'organizationalUnitName'</name>
+ </name>
+ <sup>name</sup>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.12</oid>
+ <name>
+ <name>'title'</name>
+ </name>
+ <sup>name</sup>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.13</oid>
+ <name>
+ <name>'description'</name>
+ </name>
+ <equality>caseIgnoreMatch</equality>
+ <substr>caseIgnoreSubstringsMatch</substr>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.15{1024}</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.14</oid>
+ <name>
+ <name>'searchGuide'</name>
+ </name>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.25</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.15</oid>
+ <name>
+ <name>'businessCategory'</name>
+ </name>
+ <equality>caseIgnoreMatch</equality>
+ <substr>caseIgnoreSubstringsMatch</substr>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.15{128}</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.16</oid>
+ <name>
+ <name>'postalAddress'</name>
+ </name>
+ <equality>caseIgnoreListMatch</equality>
+ <substr>caseIgnoreListSubstringsMatch</substr>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.41</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.17</oid>
+ <name>
+ <name>'postalCode'</name>
+ </name>
+ <equality>caseIgnoreMatch</equality>
+ <substr>caseIgnoreSubstringsMatch</substr>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.15{40}</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.18</oid>
+ <name>
+ <name>'postOfficeBox'</name>
+ </name>
+ <equality>caseIgnoreMatch</equality>
+ <substr>caseIgnoreSubstringsMatch</substr>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.15{40}</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.19</oid>
+ <name>
+ <name>'physicalDeliveryOfficeName'</name>
+ </name>
+ <equality>caseIgnoreMatch</equality>
+ <substr>caseIgnoreSubstringsMatch</substr>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.15{128}</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.20</oid>
+ <name>
+ <name>'telephoneNumber'</name>
+ </name>
+ <equality>telephoneNumberMatch</equality>
+ <substr>telephoneNumberSubstringsMatch</substr>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.50{32}</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.21</oid>
+ <name>
+ <name>'telexNumber'</name>
+ </name>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.52</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.22</oid>
+ <name>
+ <name>'teletexTerminalIdentifier'</name>
+ </name>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.51</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.23</oid>
+ <name>
+ <name>'facsimileTelephoneNumber'</name>
+ <name>'fax'</name>
+ </name>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.22</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.24</oid>
+ <name>
+ <name>'x121Address'</name>
+ </name>
+ <equality>numericStringMatch</equality>
+ <substr>numericStringSubstringsMatch</substr>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.36{15}</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.25</oid>
+ <name>
+ <name>'internationaliSDNNumber'</name>
+ </name>
+ <equality>numericStringMatch</equality>
+ <substr>numericStringSubstringsMatch</substr>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.36{16}</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.26</oid>
+ <name>
+ <name>'registeredAddress'</name>
+ </name>
+ <sup>postalAddress</sup>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.41</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.27</oid>
+ <name>
+ <name>'destinationIndicator'</name>
+ </name>
+ <equality>caseIgnoreMatch</equality>
+ <substr>caseIgnoreSubstringsMatch</substr>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.44{128}</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.28</oid>
+ <name>
+ <name>'preferredDeliveryMethod'</name>
+ </name>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.14</syntax>
+ <single-value>true</single-value>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.29</oid>
+ <name>
+ <name>'presentationAddress'</name>
+ </name>
+ <equality>presentationAddressMatch</equality>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.43</syntax>
+ <single-value>true</single-value>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.30</oid>
+ <name>
+ <name>'supportedApplicationContext'</name>
+ </name>
+ <equality>objectIdentifierMatch</equality>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.38</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.31</oid>
+ <name>
+ <name>'member'</name>
+ </name>
+ <sup>distinguishedName</sup>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.32</oid>
+ <name>
+ <name>'owner'</name>
+ </name>
+ <sup>distinguishedName</sup>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.33</oid>
+ <name>
+ <name>'roleOccupant'</name>
+ </name>
+ <sup>distinguishedName</sup>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.34</oid>
+ <name>
+ <name>'seeAlso'</name>
+ </name>
+ <sup>distinguishedName</sup>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.35</oid>
+ <name>
+ <name>'userPassword'</name>
+ </name>
+ <equality>octetStringMatch</equality>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.40{128}</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.36</oid>
+ <name>
+ <name>'userCertificate'</name>
+ </name>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.8</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.37</oid>
+ <name>
+ <name>'cACertificate'</name>
+ </name>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.8</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.38</oid>
+ <name>
+ <name>'authorityRevocationList'</name>
+ </name>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.9</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.39</oid>
+ <name>
+ <name>'certificateRevocationList'</name>
+ </name>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.9</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.40</oid>
+ <name>
+ <name>'crossCertificatePair'</name>
+ </name>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.10</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.42</oid>
+ <name>
+ <name>'givenName'</name>
+ <name>'gn'</name>
+ </name>
+ <sup>name</sup>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.43</oid>
+ <name>
+ <name>'initials'</name>
+ </name>
+ <sup>name</sup>
+ <desc>'The initials attribute type contains the initials of some or all of an individuals names, but not the surname(s).'</desc>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.44</oid>
+ <name>
+ <name>'generationQualifier'</name>
+ </name>
+ <desc>'e.g. Jr or II.'</desc>
+ <sup>name</sup>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.45</oid>
+ <name>
+ <name>'x500UniqueIdentifier'</name>
+ </name>
+ <equality>bitStringMatch</equality>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.6</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.46</oid>
+ <name>
+ <name>'dnQualifier'</name>
+ </name>
+ <equality>caseIgnoreMatch</equality>
+ <ordering>caseIgnoreOrderingMatch</ordering>
+ <substr>caseIgnoreSubstringsMatch</substr>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.44</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.47</oid>
+ <name>
+ <name>'enhancedSearchGuide'</name>
+ </name>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.21</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.48</oid>
+ <name>
+ <name>'protocolInformation'</name>
+ </name>
+ <equality>protocolInformationMatch</equality>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.42</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.50</oid>
+ <name>
+ <name>'uniqueMember'</name>
+ </name>
+ <equality>uniqueMemberMatch</equality>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.34</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.51</oid>
+ <name>
+ <name>'houseIdentifier'</name>
+ </name>
+ <equality>caseIgnoreMatch</equality>
+ <substr>caseIgnoreSubstringsMatch</substr>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.15{32768}</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.52</oid>
+ <name>
+ <name>'supportedAlgorithms'</name>
+ </name>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.49</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.53</oid>
+ <name>
+ <name>'deltaRevocationList'</name>
+ </name>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.9</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>2.5.4.54</oid>
+ <name>
+ <name>'dmdName'</name>
+ </name>
+ <sup>name</sup>
+ </attributetype>
+
+ <objectclass>
+ <id>2.5.6.0</id>
+ <name>
+ <name>'top'</name>
+ </name>
+ <abstract>true</abstract>
+ <must>
+ <value>objectClass</value>
+ </must>
+ </objectclass>
+
+ <objectclass>
+ <id>2.5.6.1</id>
+ <name>
+ <name>'alias'</name>
+ </name>
+ <sup>top</sup>
+ <structural>true</structural>
+ <must>
+ <value>aliasedObjectName</value>
+ </must>
+ </objectclass>
+
+ <objectclass>
+ <id>2.5.6.2</id>
+ <name>
+ <name>'country'</name>
+ </name>
+ <sup>top</sup>
+ <structural>true</structural>
+ <must>
+ <value>c</value>
+ </must>
+ <may>
+ <value>searchGuide</value>
+ <value>description</value>
+ </may>
+ </objectclass>
+
+ <objectclass>
+ <id>2.5.6.3</id>
+ <name>
+ <name>'locality'</name>
+ </name>
+ <sup>top</sup>
+ <structural>true</structural>
+ <may>
+ <value>street</value>
+ <value>seeAlso</value>
+ <value>searchGuide</value>
+ <value>st</value>
+ <value>l</value>
+ <value>description</value>
+ </may>
+ </objectclass>
+
+ <objectclass>
+ <id>2.5.6.4</id>
+ <name>
+ <name>'organization'</name>
+ </name>
+ <sup>top</sup>
+ <structural>true</structural>
+ <must>
+ <value>o</value>
+ </must>
+ <may>
+ <value>userPassword</value>
+ <value>searchGuide</value>
+ <value>seeAlso</value>
+ <value>businessCategory</value>
+ <value>x121Address</value>
+ <value>registeredAddress</value>
+ <value>destinationIndicator</value>
+ <value>preferredDeliveryMethod</value>
+ <value>telexNumber</value>
+ <value>teletexTerminalIdentifier</value>
+ <value>telephoneNumber</value>
+ <value>internationaliSDNNumber</value>
+ <value>facsimileTelephoneNumber</value>
+ <value>street</value>
+ <value>postOfficeBox</value>
+ <value>postalCode</value>
+ <value>postalAddress</value>
+ <value>physicalDeliveryOfficeName</value>
+ <value>st</value>
+ <value>l</value>
+ <value>description</value>
+ </may>
+ </objectclass>
+
+ <objectclass>
+ <id>2.5.6.5</id>
+ <name>
+ <name>'organizationalUnit'</name>
+ </name>
+ <sup>top</sup>
+ <structural>true</structural>
+ <must>
+ <value>ou</value>
+ </must>
+ <may>
+ <value>userPassword</value>
+ <value>searchGuide</value>
+ <value>seeAlso</value>
+ <value>businessCategory</value>
+ <value>x121Address</value>
+ <value>registeredAddress</value>
+ <value>destinationIndicator</value>
+ <value>preferredDeliveryMethod</value>
+ <value>telexNumber</value>
+ <value>teletexTerminalIdentifier</value>
+ <value>telephoneNumber</value>
+ <value>internationaliSDNNumber</value>
+ <value>facsimileTelephoneNumber</value>
+ <value>street</value>
+ <value>postOfficeBox</value>
+ <value>postalCode</value>
+ <value>postalAddress</value>
+ <value>physicalDeliveryOfficeName</value>
+ <value>st</value>
+ <value>l</value>
+ <value>description</value>
+ </may>
+ </objectclass>
+
+ <objectclass>
+ <id>2.5.6.6</id>
+ <name>
+ <name>'person'</name>
+ </name>
+ <sup>top</sup>
+ <structural>true</structural>
+ <must>
+ <value>sn</value>
+ <value>cn</value>
+ </must>
+ <may>
+ <value>userPassword</value>
+ <value>telephoneNumber</value>
+ <value>seeAlso</value>
+ <value>description</value>
+ </may>
+ </objectclass>
+
+ <objectclass>
+ <id>2.5.6.7</id>
+ <name>
+ <name>'organizationalPerson'</name>
+ </name>
+ <sup>person</sup>
+ <structural>true</structural>
+ <may>
+ <value>title</value>
+ <value>x121Address</value>
+ <value>registeredAddress</value>
+ <value>destinationIndicator</value>
+ <value>preferredDeliveryMethod</value>
+ <value>telexNumber</value>
+ <value>teletexTerminalIdentifier</value>
+ <value>telephoneNumber</value>
+ <value>internationaliSDNNumber</value>
+ <value>facsimileTelephoneNumber</value>
+ <value>street</value>
+ <value>postOfficeBox</value>
+ <value>postalCode</value>
+ <value>postalAddress</value>
+ <value>physicalDeliveryOfficeName</value>
+ <value>ou</value>
+ <value>st</value>
+ <value>l</value>
+ </may>
+ </objectclass>
+
+ <objectclass>
+ <id>2.5.6.8</id>
+ <name>
+ <name>'organizationalRole'</name>
+ </name>
+ <sup>top</sup>
+ <structural>true</structural>
+ <must>
+ <value>cn</value>
+ </must>
+ <may>
+ <value>x121Address</value>
+ <value>registeredAddress</value>
+ <value>destinationIndicator</value>
+ <value>preferredDeliveryMethod</value>
+ <value>telexNumber</value>
+ <value>teletexTerminalIdentifier</value>
+ <value>telephoneNumber</value>
+ <value>internationaliSDNNumber</value>
+ <value>facsimileTelephoneNumber</value>
+ <value>seeAlso</value>
+ <value>roleOccupant</value>
+ <value>preferredDeliveryMethod</value>
+ <value>street</value>
+ <value>postOfficeBox</value>
+ <value>postalCode</value>
+ <value>postalAddress</value>
+ <value>physicalDeliveryOfficeName</value>
+ <value>ou</value>
+ <value>st</value>
+ <value>l</value>
+ <value>description</value>
+ </may>
+ </objectclass>
+
+ <objectclass>
+ <id>2.5.6.9</id>
+ <name>
+ <name>'groupOfNames'</name>
+ </name>
+ <sup>top</sup>
+ <structural>true</structural>
+ <must>
+ <value>member</value>
+ <value>cn</value>
+ </must>
+ <may>
+ <value>businessCategory</value>
+ <value>seeAlso</value>
+ <value>owner</value>
+ <value>ou</value>
+ <value>o</value>
+ <value>description</value>
+ </may>
+ </objectclass>
+
+ <objectclass>
+ <id>2.5.6.10</id>
+ <name>
+ <name>'residentialPerson'</name>
+ </name>
+ <sup>person</sup>
+ <structural>true</structural>
+ <must>
+ <value>l</value>
+ </must>
+ <may>
+ <value>businessCategory</value>
+ <value>x121Address</value>
+ <value>registeredAddress</value>
+ <value>destinationIndicator</value>
+ <value>preferredDeliveryMethod</value>
+ <value>telexNumber</value>
+ <value>teletexTerminalIdentifier</value>
+ <value>telephoneNumber</value>
+ <value>internationaliSDNNumber</value>
+ <value>facsimileTelephoneNumber</value>
+ <value>preferredDeliveryMethod</value>
+ <value>street</value>
+ <value>postOfficeBox</value>
+ <value>postalCode</value>
+ <value>postalAddress</value>
+ <value>physicalDeliveryOfficeName</value>
+ <value>st</value>
+ <value>l</value>
+ </may>
+ </objectclass>
+
+ <objectclass>
+ <id>2.5.6.11</id>
+ <name>
+ <name>'applicationProcess'</name>
+ </name>
+ <sup>top</sup>
+ <structural>true</structural>
+ <must>
+ <value>cn</value>
+ </must>
+ <may>
+ <value>seeAlso</value>
+ <value>ou</value>
+ <value>l</value>
+ <value>description</value>
+ </may>
+ </objectclass>
+
+ <objectclass>
+ <id>2.5.6.12</id>
+ <name>
+ <name>'applicationEntity'</name>
+ </name>
+ <sup>top</sup>
+ <structural>true</structural>
+ <must>
+ <value>presentationAddress</value>
+ <value>cn</value>
+ </must>
+ <may>
+ <value>supportedApplicationContext</value>
+ <value>seeAlso</value>
+ <value>ou</value>
+ <value>o</value>
+ <value>l</value>
+ <value>description</value>
+ </may>
+ </objectclass>
+
+ <objectclass>
+ <id>2.5.6.13</id>
+ <name>
+ <name>'dSA'</name>
+ </name>
+ <sup>applicationEntity</sup>
+ <structural>true</structural>
+ <may>
+ <value>knowledgeInformation</value>
+ </may>
+ </objectclass>
+
+ <objectclass>
+ <id>2.5.6.14</id>
+ <name>
+ <name>'device'</name>
+ </name>
+ <sup>top</sup>
+ <structural>true</structural>
+ <must>
+ <value>cn</value>
+ </must>
+ <may>
+ <value>serialNumber</value>
+ <value>seeAlso</value>
+ <value>owner</value>
+ <value>ou</value>
+ <value>o</value>
+ <value>l</value>
+ <value>description</value>
+ </may>
+ </objectclass>
+
+ <objectclass>
+ <id>2.5.6.15</id>
+ <name>
+ <name>'strongAuthenticationUser'</name>
+ </name>
+ <sup>top</sup>
+ <auxiliary>true</auxiliary>
+ <must>
+ <value>userCertificate</value>
+ </must>
+ </objectclass>
+
+ <objectclass>
+ <id>2.5.6.16</id>
+ <name>
+ <name>'certificationAuthority'</name>
+ </name>
+ <sup>top</sup>
+ <auxiliary>true</auxiliary>
+ <must>
+ <value>authorityRevocationList</value>
+ <value>certificateRevocationList</value>
+ <value>cACertificate</value>
+ </must>
+ <may>
+ <value>crossCertificatePair</value>
+ </may>
+ </objectclass>
+
+ <objectclass>
+ <id>2.5.6.17</id>
+ <name>
+ <name>'groupOfUniqueNames'</name>
+ </name>
+ <sup>top</sup>
+ <structural>true</structural>
+ <must>
+ <value>uniqueMember</value>
+ <value>cn</value>
+ </must>
+ <may>
+ <value>businessCategory</value>
+ <value>seeAlso</value>
+ <value>owner</value>
+ <value>ou</value>
+ <value>o</value>
+ <value>description</value>
+ </may>
+ </objectclass>
+
+ <objectclass>
+ <id>2.5.6.18</id>
+ <name>
+ <name>'userSecurityInformation'</name>
+ </name>
+ <sup>top</sup>
+ <auxiliary>true</auxiliary>
+ <may>
+ <value>supportedAlgorithms</value>
+ </may>
+ </objectclass>
+
+ <objectclass>
+ <id>2.5.6.16.2</id>
+ <name>
+ <name>'certificationAuthority-V2'</name>
+ </name>
+ <sup>certificationAuthority</sup>
+ <auxiliary>true</auxiliary>
+ <may>
+ <value>deltaRevocationList</value>
+ </may>
+ </objectclass>
+
+ <objectclass>
+ <id>2.5.6.19</id>
+ <name>
+ <name>'cRLDistributionPoint'</name>
+ </name>
+ <sup>top</sup>
+ <structural>true</structural>
+ <must>
+ <value>cn</value>
+ </must>
+ <may>
+ <value>certificateRevocationList</value>
+ <value>authorityRevocationList</value>
+ <value>deltaRevocationList</value>
+ </may>
+ </objectclass>
+
+ <objectclass>
+ <id>2.5.6.20</id>
+ <name>
+ <name>'dmd'</name>
+ </name>
+ <sup>top</sup>
+ <structural>true</structural>
+ <must>
+ <value>dmdName</value>
+ </must>
+ <may>
+ <value>userPassword</value>
+ <value>searchGuide</value>
+ <value>seeAlso</value>
+ <value>businessCategory</value>
+ <value>x121Address</value>
+ <value>registeredAddress</value>
+ <value>destinationIndicator</value>
+ <value>preferredDeliveryMethod</value>
+ <value>telexNumber</value>
+ <value>teletexTerminalIdentifier</value>
+ <value>telephoneNumber</value>
+ <value>internationaliSDNNumber</value>
+ <value>facsimileTelephoneNumber</value>
+ <value>street</value>
+ <value>postOfficeBox</value>
+ <value>postalCode</value>
+ <value>postalAddress</value>
+ <value>physicalDeliveryOfficeName</value>
+ <value>st</value>
+ <value>l</value>
+ <value>description</value>
+ </may>
+ </objectclass>
+
+ <objectclass>
+ <id>1.3.6.1.4.1.1466.101.120.111</id>
+ <name>
+ <name>'extensibleObject'</name>
+ </name>
+ <desc>'RFC2252: extensible object'</desc>
+ <sup>top</sup>
+ <auxiliary>true</auxiliary>
+ </objectclass>
+
+ <attributetype>
+ <oid>1.3.6.1.4.1.250.1.57</oid>
+ <name>
+ <name>'labeledURI'</name>
+ </name>
+ <desc>'RFC2079: Uniform Resource Identifier with optional label'</desc>
+ <equality>caseExactMatch</equality>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.15</syntax>
+ </attributetype>
+
+ <objectclass>
+ <id>1.3.6.1.4.1.250.3.15</id>
+ <name>
+ <name>'labeledURIObject'</name>
+ </name>
+ <desc>'RFC2079: object that contains the URI attribute type'</desc>
+ <may>
+ <value>labeledURI</value>
+ </may>
+ <sup>top</sup>
+ <auxiliary>true</auxiliary>
+ </objectclass>
+
+ <objectclass>
+ <id>1.3.6.1.4.1.1466.101.119.2</id>
+ <name>
+ <name>'dynamicObject'</name>
+ </name>
+ <desc>'RFC2589: Dynamic Object'</desc>
+ <sup>top</sup>
+ <auxiliary>true</auxiliary>
+ </objectclass>
+
+ <attributetype>
+ <oid>1.3.6.1.4.1.1466.101.119.3</oid>
+ <name>
+ <name>'entryTtl'</name>
+ </name>
+ <desc>'RFC2589: entry time-to-live'</desc>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.27</syntax>
+ <single-value>true</single-value>
+ <no-user-modification>true</no-user-modification>
+ <usage>dSAOperation</usage>
+ </attributetype>
+
+ <attributetype>
+ <oid>1.3.6.1.4.1.1466.101.119.4</oid>
+ <name>
+ <name>'dynamicSubtrees'</name>
+ </name>
+ <desc>'RFC2589: dynamic subtrees'</desc>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.12</syntax>
+ <no-user-modification>true</no-user-modification>
+ <usage>dSAOperation</usage>
+ </attributetype>
+
+ <attributetype>
+ <oid>0.9.2342.19200300.100.1.1</oid>
+ <name>
+ <name>'uid'</name>
+ <name>'userid'</name>
+ </name>
+ <desc>'RFC1274: user identifier'</desc>
+ <equality>caseIgnoreMatch</equality>
+ <substr>caseIgnoreSubstringsMatch</substr>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.15{256}</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>0.9.2342.19200300.100.1.3</oid>
+ <name>
+ <name>'mail'</name>
+ <name>'rfc822Mailbox'</name>
+ </name>
+ <desc>'RFC1274: RFC822 Mailbox'</desc>
+ <equality>caseIgnoreIA5Match</equality>
+ <substr>caseIgnoreIA5SubstringsMatch</substr>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.26{256}</syntax>
+ </attributetype>
+
+ <objectclass>
+ <id>0.9.2342.19200300.100.4.19</id>
+ <name>
+ <name>'simpleSecurityObject'</name>
+ </name>
+ <desc>'RFC1274: simple security object'</desc>
+ <sup>top</sup>
+ <auxiliary>true</auxiliary>
+ <must>
+ <value>userPassword</value>
+ </must>
+ </objectclass>
+
+ <attributetype>
+ <oid>0.9.2342.19200300.100.1.25</oid>
+ <name>
+ <name>'dc'</name>
+ <name>'domainComponent'</name>
+ </name>
+ <desc>'RFC1274/2247: domain component'</desc>
+ <equality>caseIgnoreIA5Match</equality>
+ <substr>caseIgnoreIA5SubstringsMatch</substr>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.26</syntax>
+ <single-value>true</single-value>
+ </attributetype>
+
+ <objectclass>
+ <id>1.3.6.1.4.1.1466.344</id>
+ <name>
+ <name>'dcObject'</name>
+ </name>
+ <desc>'RFC2247: domain component object'</desc>
+ <sup>top</sup>
+ <auxiliary>true</auxiliary>
+ <must>
+ <value>dc</value>
+ </must>
+ </objectclass>
+
+ <objectclass>
+ <id>1.3.6.1.1.3.1</id>
+ <name>
+ <name>'uidObject'</name>
+ </name>
+ <desc>'RFC2377: uid object'</desc>
+ <sup>top</sup>
+ <auxiliary>true</auxiliary>
+ <must>
+ <value>uid</value>
+ </must>
+ </objectclass>
+
+ <attributetype>
+ <oid>2.16.840.1.113730.3.1.34</oid>
+ <name>
+ <name>'ref'</name>
+ </name>
+ <desc>'Named referral'</desc>
+ <equality>caseExactMatch</equality>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.15</syntax>
+ <usage>distributedOperation</usage>
+ </attributetype>
+
+ <objectclass>
+ <id>2.16.840.1.113730.3.2.6</id>
+ <name>
+ <name>'referral'</name>
+ </name>
+ <desc>'Named referral object'</desc>
+ <sup>top</sup>
+ <structural>true</structural>
+ <must>
+ <value>ref</value>
+ </must>
+ </objectclass>
+
+ <objectclass>
+ <id>2.16.840.1.113719.2.142.6.1.1</id>
+ <name>
+ <name>'LDAPsubEntry'</name>
+ </name>
+ <desc>'LDAP Subentry'</desc>
+ <sup>top</sup>
+ <structural>true</structural>
+ <may>
+ <value>cn</value>
+ </may>
+ </objectclass>
+
+ <objectclass>
+ <id>1.3.6.1.4.1.4203.1.4.1</id>
+ <name>
+ <name>'OpenLDAProotDSE'</name>
+ <name>'LDAProotDSE'</name>
+ </name>
+ <desc>'OpenLDAP Root DSE object'</desc>
+ <sup>top</sup>
+ <structural>true</structural>
+ <may>
+ <value>cn</value>
+ </may>
+ </objectclass>
+
+ <attributetype>
+ <oid>0.9.2342.19200300.100.1.37</oid>
+ <name>
+ <name>'associatedDomain'</name>
+ </name>
+ <equality>caseIgnoreIA5Match</equality>
+ <substr>caseIgnoreIA5SubstringsMatch</substr>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.26</syntax>
+ </attributetype>
+
+ <attributetype>
+ <oid>1.3.6.1.4.1.250.1.32</oid>
+ <name>
+ <name>'krbName'</name>
+ <name>'kerberosName'</name>
+ </name>
+ <desc>'Kerberos Name'</desc>
+ <equality>caseIgnoreIA5Match</equality>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.26</syntax>
+ <single-value>true</single-value>
+ </attributetype>
+
+ <attributetype>
+ <oid>1.3.6.1.4.1.4203.1.3.5</oid>
+ <name>
+ <name>'supportedFeatures'</name>
+ </name>
+ <desc>'features supported by the server'</desc>
+ <equality>objectIdentifierMatch</equality>
+ <syntax>1.3.6.1.4.1.1466.115.121.1.38</syntax>
+ <usage>dSAOperation</usage>
+ </attributetype>
+
+ <attributetype>
+ <oid>1.3.6.1.4.1.4203.1.3.1</oid>
+ <name>
+ <name>'entry'</name>
+ </name>
+ <desc>'OpenLDAP ACL entry pseudo-attribute'</desc>
+ <syntax>1.3.6.1.4.1.4203.1.1.1</syntax>
+ <single-value>true</single-value>
+ <no-user-modification>true</no-user-modification>
+ <usage>dSAOperation</usage>
+ </attributetype>
+
+ <attributetype>
+ <oid>1.3.6.1.4.1.4203.1.3.2</oid>
+ <name>
+ <name>'children'</name>
+ </name>
+ <desc>'OpenLDAP ACL children pseudo-attribute'</desc>
+ <syntax>1.3.6.1.4.1.4203.1.1.1</syntax>
+ <single-value>true</single-value>
+ <no-user-modification>true</no-user-modification>
+ <usage>dSAOperation</usage>
+ </attributetype>
+
+ <attributetype>
+ <oid>1.3.6.1.4.1.4203.666.1.5</oid>
+ <name>
+ <name>'OpenLDAPaci'</name>
+ </name>
+ <desc>'OpenLDAP access control information'</desc>
+ <equality>OpenLDAPaciMatch</equality>
+ <syntax>1.3.6.1.4.1.4203.666.2.1</syntax>
+ <usage>directoryOperation</usage>
+ </attributetype>
+</configuration>
Added: incubator/directory/eve/branches/start/src/schema/cosine.schema
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/schema/cosine.schema Thu Jun 24 00:06:35 2004
@@ -0,0 +1,2525 @@
+# $OpenLDAP: pkg/ldap/servers/slapd/schema/cosine.schema,v 1.6.2.7 2002/01/09 16:49:09 kurt Exp $
+#
+# RFC1274: Cosine and Internet X.500 schema
+#
+# This file contains LDAPv3 schema derived from X.500 COSINE "pilot"
+# schema. As this schema was defined for X.500(89), some
+# oddities were introduced in the mapping to LDAPv3. The
+# mappings were based upon: draft-ietf-asid-ldapv3-attributes-03.txt
+# (a work in progress)
+#
+# Note: It seems that the pilot schema evolved beyond what was
+# described in RFC1274. However, this document attempts to describes
+# RFC1274 as published.
+#
+# Depends on core.schema
+
+
+# Network Working Group P. Barker
+# Request for Comments: 1274 S. Kille
+# University College London
+# November 1991
+#
+# The COSINE and Internet X.500 Schema
+#
+# [trimmed]
+#
+# Abstract
+#
+# This document suggests an X.500 Directory Schema, or Naming
+# Architecture, for use in the COSINE and Internet X.500 pilots. The
+# schema is independent of any specific implementation. As well as
+# indicating support for the standard object classes and attributes, a
+# large number of generally useful object classes and attributes are
+# also defined. An appendix to this document includes a machine
+# processable version of the schema.
+#
+# [trimmed]
+
+# 7. Object Identifiers
+#
+# Some additional object identifiers are defined for this schema.
+# These are also reproduced in Appendix C.
+#
+# data OBJECT IDENTIFIER ::= {ccitt 9}
+# pss OBJECT IDENTIFIER ::= {data 2342}
+# ucl OBJECT IDENTIFIER ::= {pss 19200300}
+# pilot OBJECT IDENTIFIER ::= {ucl 100}
+#
+# pilotAttributeType OBJECT IDENTIFIER ::= {pilot 1}
+# pilotAttributeSyntax OBJECT IDENTIFIER ::= {pilot 3}
+# pilotObjectClass OBJECT IDENTIFIER ::= {pilot 4}
+# pilotGroups OBJECT IDENTIFIER ::= {pilot 10}
+#
+# iA5StringSyntax OBJECT IDENTIFIER ::= {pilotAttributeSyntax 4}
+# caseIgnoreIA5StringSyntax OBJECT IDENTIFIER ::=
+# {pilotAttributeSyntax 5}
+#
+# 8. Object Classes
+# [relocated after 9]
+
+#
+# 9. Attribute Types
+#
+# 9.1. X.500 standard attribute types
+#
+# A number of generally useful attribute types are defined in X.520,
+# and these are supported. Refer to that document for descriptions of
+# the suggested usage of these attribute types. The ASN.1 for these
+# attribute types is reproduced for completeness in Appendix C.
+#
+# 9.2. X.400 standard attribute types
+#
+# The standard X.400 attribute types are supported. See X.402 for full
+# details. The ASN.1 for these attribute types is reproduced in
+# Appendix C.
+#
+# 9.3. COSINE/Internet attribute types
+#
+# This section describes all the attribute types defined for use in the
+# COSINE and Internet pilots. Descriptions are given as to the
+# suggested usage of these attribute types. The ASN.1 for these
+# attribute types is reproduced in Appendix C.
+#
+# 9.3.1. Userid
+#
+# The Userid attribute type specifies a computer system login name.
+#
+# userid ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-user-identifier))
+# ::= {pilotAttributeType 1}
+#
+#(in core.schema)
+##attributetype ( 0.9.2342.19200300.100.1.1 NAME ( 'uid' 'userid' )
+## EQUALITY caseIgnoreMatch
+## SUBSTR caseIgnoreSubstringsMatch
+## SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+
+# 9.3.2. Text Encoded O/R Address
+#
+# The Text Encoded O/R Address attribute type specifies a text encoding
+# of an X.400 O/R address, as specified in RFC 987. The use of this
+# attribute is deprecated as the attribute is intended for interim use
+# only. This attribute will be the first candidate for the attribute
+# expiry mechanisms!
+#
+# textEncodedORAddress ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-text-encoded-or-address))
+# ::= {pilotAttributeType 2}
+#
+attributetype ( 0.9.2342.19200300.100.1.2 NAME 'textEncodedORAddress'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+
+# 9.3.3. RFC 822 Mailbox
+#
+# The RFC822 Mailbox attribute type specifies an electronic mailbox
+# attribute following the syntax specified in RFC 822. Note that this
+# attribute should not be used for greybook or other non-Internet order
+# mailboxes.
+#
+# rfc822Mailbox ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreIA5StringSyntax
+# (SIZE (1 .. ub-rfc822-mailbox))
+# ::= {pilotAttributeType 3}
+#
+#(in core.schema)
+##attributetype ( 0.9.2342.19200300.100.1.3 NAME ( 'mail' 'rfc822Mailbox' )
+## EQUALITY caseIgnoreIA5Match
+## SUBSTR caseIgnoreIA5SubstringsMatch
+## SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
+
+# 9.3.4. Information
+#
+# The Information attribute type specifies any general information
+# pertinent to an object. It is recommended that specific usage of
+# this attribute type is avoided, and that specific requirements are
+# met by other (possibly additional) attribute types.
+#
+# info ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-information))
+# ::= {pilotAttributeType 4}
+#
+attributetype ( 0.9.2342.19200300.100.1.4 NAME 'info'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{2048} )
+
+
+# 9.3.5. Favourite Drink
+#
+# The Favourite Drink attribute type specifies the favourite drink of
+# an object (or person).
+#
+# favouriteDrink ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-favourite-drink))
+# ::= {pilotAttributeType 5}
+#
+attributetype ( 0.9.2342.19200300.100.1.5
+ NAME ( 'drink' 'favouriteDrink' )
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+
+# 9.3.6. Room Number
+#
+# The Room Number attribute type specifies the room number of an
+# object. Note that the commonName attribute should be used for naming
+# room objects.
+#
+# roomNumber ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-room-number))
+# ::= {pilotAttributeType 6}
+#
+attributetype ( 0.9.2342.19200300.100.1.6 NAME 'roomNumber'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+
+# 9.3.7. Photo
+#
+# The Photo attribute type specifies a "photograph" for an object.
+# This should be encoded in G3 fax as explained in recommendation T.4,
+# with an ASN.1 wrapper to make it compatible with an X.400 BodyPart as
+# defined in X.420.
+#
+# IMPORT G3FacsimileBodyPart FROM { mhs-motis ipms modules
+# information-objects }
+#
+# photo ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# CHOICE {
+# g3-facsimile [3] G3FacsimileBodyPart
+# }
+# (SIZE (1 .. ub-photo))
+# ::= {pilotAttributeType 7}
+#
+attributetype ( 0.9.2342.19200300.100.1.7 NAME 'photo'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.23{25000} )
+
+# 9.3.8. User Class
+#
+# The User Class attribute type specifies a category of computer user.
+# The semantics placed on this attribute are for local interpretation.
+# Examples of current usage od this attribute in academia are
+# undergraduate student, researcher, lecturer, etc. Note that the
+# organizationalStatus attribute may now often be preferred as it makes
+# no distinction between computer users and others.
+#
+# userClass ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-user-class))
+# ::= {pilotAttributeType 8}
+#
+attributetype ( 0.9.2342.19200300.100.1.8 NAME 'userClass'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+
+# 9.3.9. Host
+#
+# The Host attribute type specifies a host computer.
+#
+# host ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-host))
+# ::= {pilotAttributeType 9}
+#
+attributetype ( 0.9.2342.19200300.100.1.9 NAME 'host'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+
+# 9.3.10. Manager
+#
+# The Manager attribute type specifies the manager of an object
+# represented by an entry.
+#
+# manager ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# distinguishedNameSyntax
+# ::= {pilotAttributeType 10}
+#
+attributetype ( 0.9.2342.19200300.100.1.10 NAME 'manager'
+ EQUALITY distinguishedNameMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )
+
+# 9.3.11. Document Identifier
+#
+# The Document Identifier attribute type specifies a unique identifier
+# for a document.
+#
+# documentIdentifier ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-document-identifier))
+# ::= {pilotAttributeType 11}
+#
+attributetype ( 0.9.2342.19200300.100.1.11 NAME 'documentIdentifier'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+
+# 9.3.12. Document Title
+#
+# The Document Title attribute type specifies the title of a document.
+#
+# documentTitle ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-document-title))
+# ::= {pilotAttributeType 12}
+#
+attributetype ( 0.9.2342.19200300.100.1.12 NAME 'documentTitle'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+
+# 9.3.13. Document Version
+#
+# The Document Version attribute type specifies the version number of a
+# document.
+#
+# documentVersion ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-document-version))
+# ::= {pilotAttributeType 13}
+#
+attributetype ( 0.9.2342.19200300.100.1.13 NAME 'documentVersion'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+
+# 9.3.14. Document Author
+#
+# The Document Author attribute type specifies the distinguished name
+# of the author of a document.
+#
+# documentAuthor ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# distinguishedNameSyntax
+# ::= {pilotAttributeType 14}
+#
+attributetype ( 0.9.2342.19200300.100.1.14 NAME 'documentAuthor'
+ EQUALITY distinguishedNameMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )
+
+# 9.3.15. Document Location
+#
+# The Document Location attribute type specifies the location of the
+# document original.
+#
+# documentLocation ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-document-location))
+# ::= {pilotAttributeType 15}
+#
+attributetype ( 0.9.2342.19200300.100.1.15 NAME 'documentLocation'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+
+# 9.3.16. Home Telephone Number
+#
+# The Home Telephone Number attribute type specifies a home telephone
+# number associated with a person. Attribute values should follow the
+# agreed format for international telephone numbers: i.e., "+44 71 123
+# 4567".
+#
+# homeTelephoneNumber ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# telephoneNumberSyntax
+# ::= {pilotAttributeType 20}
+#
+attributetype ( 0.9.2342.19200300.100.1.20
+ NAME ( 'homePhone' 'homeTelephoneNumber' )
+ EQUALITY telephoneNumberMatch
+ SUBSTR telephoneNumberSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )
+
+# 9.3.17. Secretary
+#
+# The Secretary attribute type specifies the secretary of a person.
+# The attribute value for Secretary is a distinguished name.
+#
+# secretary ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# distinguishedNameSyntax
+# ::= {pilotAttributeType 21}
+#
+attributetype ( 0.9.2342.19200300.100.1.21 NAME 'secretary'
+ EQUALITY distinguishedNameMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )
+
+# 9.3.18. Other Mailbox
+#
+# The Other Mailbox attribute type specifies values for electronic
+# mailbox types other than X.400 and rfc822.
+#
+# otherMailbox ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# SEQUENCE {
+# mailboxType PrintableString, -- e.g. Telemail
+# mailbox IA5String -- e.g. X378:Joe
+# }
+# ::= {pilotAttributeType 22}
+#
+attributetype ( 0.9.2342.19200300.100.1.22 NAME 'otherMailbox'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.39 )
+
+# 9.3.19. Last Modified Time
+#
+# The Last Modified Time attribute type specifies the last time, in UTC
+# time, that an entry was modified. Ideally, this attribute should be
+# maintained by the DSA.
+#
+# lastModifiedTime ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# uTCTimeSyntax
+# ::= {pilotAttributeType 23}
+#
+## OBSOLETE
+#attributetype ( 0.9.2342.19200300.100.1.23 NAME 'lastModifiedTime'
+# DESC 'RFC1274: time of last modify, replaced by modifyTimestamp'
+# OBSOLETE
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.53
+# USAGE directoryOperation )
+
+# 9.3.20. Last Modified By
+#
+# The Last Modified By attribute specifies the distinguished name of
+# the last user to modify the associated entry. Ideally, this
+# attribute should be maintained by the DSA.
+#
+# lastModifiedBy ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# distinguishedNameSyntax
+# ::= {pilotAttributeType 24}
+#
+
+## OBSOLETE
+#attributetype ( 0.9.2342.19200300.100.1.24 NAME 'lastModifiedBy'
+# DESC 'RFC1274: last modifier, replaced by modifiersName'
+# OBSOLETE
+# EQUALITY distinguishedNameMatch
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
+# USAGE directoryOperation )
+
+# 9.3.21. Domain Component
+#
+# The Domain Component attribute type specifies a DNS/NRS domain. For
+# example, "uk" or "ac".
+#
+# domainComponent ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreIA5StringSyntax
+# SINGLE VALUE
+# ::= {pilotAttributeType 25}
+#
+##(in core.schema)
+##attributetype ( 0.9.2342.19200300.100.1.25 NAME ( 'dc' 'domainComponent' )
+## EQUALITY caseIgnoreIA5Match
+## SUBSTR caseIgnoreIA5SubstringsMatch
+## SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+
+# 9.3.22. DNS ARecord
+#
+# The A Record attribute type specifies a type A (Address) DNS resource
+# record [6] [7].
+#
+# aRecord ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# DNSRecordSyntax
+# ::= {pilotAttributeType 26}
+#
+## incorrect syntax?
+attributetype ( 0.9.2342.19200300.100.1.26 NAME 'aRecord'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+## missing from RFC1274
+## incorrect syntax?
+attributetype ( 0.9.2342.19200300.100.1.27 NAME 'mDRecord'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+# 9.3.23. MX Record
+#
+# The MX Record attribute type specifies a type MX (Mail Exchange) DNS
+# resource record [6] [7].
+#
+# mXRecord ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# DNSRecordSyntax
+# ::= {pilotAttributeType 28}
+#
+## incorrect syntax!!
+attributetype ( 0.9.2342.19200300.100.1.28 NAME 'mXRecord'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+# 9.3.24. NS Record
+#
+# The NS Record attribute type specifies an NS (Name Server) DNS
+# resource record [6] [7].
+#
+# nSRecord ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# DNSRecordSyntax
+# ::= {pilotAttributeType 29}
+#
+## incorrect syntax!!
+attributetype ( 0.9.2342.19200300.100.1.29 NAME 'nSRecord'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+# 9.3.25. SOA Record
+#
+# The SOA Record attribute type specifies a type SOA (Start of
+# Authority) DNS resorce record [6] [7].
+#
+# sOARecord ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# DNSRecordSyntax
+# ::= {pilotAttributeType 30}
+#
+## incorrect syntax!!
+attributetype ( 0.9.2342.19200300.100.1.30 NAME 'sOARecord'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+# 9.3.26. CNAME Record
+#
+# The CNAME Record attribute type specifies a type CNAME (Canonical
+# Name) DNS resource record [6] [7].
+#
+# cNAMERecord ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# iA5StringSyntax
+# ::= {pilotAttributeType 31}
+#
+## incorrect syntax!!
+attributetype ( 0.9.2342.19200300.100.1.31 NAME 'cNAMERecord'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+# 9.3.27. Associated Domain
+#
+# The Associated Domain attribute type specifies a DNS or NRS domain
+# which is associated with an object in the DIT. For example, the entry
+# in the DIT with a distinguished name "C=GB, O=University College
+# London" would have an associated domain of "UCL.AC.UK. Note that all
+# domains should be represented in rfc822 order. See [3] for more
+# details of usage of this attribute.
+#
+# associatedDomain ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreIA5StringSyntax
+# ::= {pilotAttributeType 37}
+#
+#attributetype ( 0.9.2342.19200300.100.1.37 NAME 'associatedDomain'
+# EQUALITY caseIgnoreIA5Match
+# SUBSTR caseIgnoreIA5SubstringsMatch
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+# 9.3.28. Associated Name
+#
+# The Associated Name attribute type specifies an entry in the
+# organisational DIT associated with a DNS/NRS domain. See [3] for
+# more details of usage of this attribute.
+#
+# associatedName ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# distinguishedNameSyntax
+# ::= {pilotAttributeType 38}
+#
+attributetype ( 0.9.2342.19200300.100.1.38 NAME 'associatedName'
+ EQUALITY distinguishedNameMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )
+
+# 9.3.29. Home postal address
+#
+# The Home postal address attribute type specifies a home postal
+# address for an object. This should be limited to up to 6 lines of 30
+# characters each.
+#
+# homePostalAddress ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# postalAddress
+# MATCHES FOR EQUALITY
+# ::= {pilotAttributeType 39}
+#
+attributetype ( 0.9.2342.19200300.100.1.39 NAME 'homePostalAddress'
+ EQUALITY caseIgnoreListMatch
+ SUBSTR caseIgnoreListSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )
+
+# 9.3.30. Personal Title
+#
+# The Personal Title attribute type specifies a personal title for a
+# person. Examples of personal titles are "Ms", "Dr", "Prof" and "Rev".
+#
+# personalTitle ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-personal-title))
+# ::= {pilotAttributeType 40}
+#
+attributetype ( 0.9.2342.19200300.100.1.40 NAME 'personalTitle'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+
+# 9.3.31. Mobile Telephone Number
+#
+# The Mobile Telephone Number attribute type specifies a mobile
+# telephone number associated with a person. Attribute values should
+# follow the agreed format for international telephone numbers: i.e.,
+# "+44 71 123 4567".
+#
+# mobileTelephoneNumber ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# telephoneNumberSyntax
+# ::= {pilotAttributeType 41}
+#
+attributetype ( 0.9.2342.19200300.100.1.41
+ NAME ( 'mobile' 'mobileTelephoneNumber' )
+ EQUALITY telephoneNumberMatch
+ SUBSTR telephoneNumberSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )
+
+# 9.3.32. Pager Telephone Number
+#
+# The Pager Telephone Number attribute type specifies a pager telephone
+# number for an object. Attribute values should follow the agreed
+# format for international telephone numbers: i.e., "+44 71 123 4567".
+#
+# pagerTelephoneNumber ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# telephoneNumberSyntax
+# ::= {pilotAttributeType 42}
+#
+attributetype ( 0.9.2342.19200300.100.1.42
+ NAME ( 'pager' 'pagerTelephoneNumber' )
+ EQUALITY telephoneNumberMatch
+ SUBSTR telephoneNumberSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )
+
+# 9.3.33. Friendly Country Name
+#
+# The Friendly Country Name attribute type specifies names of countries
+# in human readable format. The standard attribute country name must
+# be one of the two-letter codes defined in ISO 3166.
+#
+# friendlyCountryName ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# ::= {pilotAttributeType 43}
+#
+attributetype ( 0.9.2342.19200300.100.1.43
+ NAME ( 'co' 'friendlyCountryName' )
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+# 9.3.34. Unique Identifier
+#
+# The Unique Identifier attribute type specifies a "unique identifier"
+# for an object represented in the Directory. The domain within which
+# the identifier is unique, and the exact semantics of the identifier,
+# are for local definition. For a person, this might be an
+# institution-wide payroll number. For an organisational unit, it
+# might be a department code.
+#
+# uniqueIdentifier ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-unique-identifier))
+# ::= {pilotAttributeType 44}
+#
+attributetype ( 0.9.2342.19200300.100.1.44 NAME 'uniqueIdentifier'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+
+# 9.3.35. Organisational Status
+#
+# The Organisational Status attribute type specifies a category by
+# which a person is often referred to in an organisation. Examples of
+# usage in academia might include undergraduate student, researcher,
+# lecturer, etc.
+#
+# A Directory administrator should probably consider carefully the
+# distinctions between this and the title and userClass attributes.
+#
+# organizationalStatus ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-organizational-status))
+# ::= {pilotAttributeType 45}
+#
+attributetype ( 0.9.2342.19200300.100.1.45 NAME 'organizationalStatus'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+
+# 9.3.36. Janet Mailbox
+#
+# The Janet Mailbox attribute type specifies an electronic mailbox
+# attribute following the syntax specified in the Grey Book of the
+# Coloured Book series. This attribute is intended for the convenience
+# of U.K users unfamiliar with rfc822 and little-endian mail addresses.
+# Entries using this attribute MUST also include an rfc822Mailbox
+# attribute.
+#
+# janetMailbox ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreIA5StringSyntax
+# (SIZE (1 .. ub-janet-mailbox))
+# ::= {pilotAttributeType 46}
+#
+attributetype ( 0.9.2342.19200300.100.1.46 NAME 'janetMailbox'
+ EQUALITY caseIgnoreIA5Match
+ SUBSTR caseIgnoreIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
+
+# 9.3.37. Mail Preference Option
+#
+# An attribute to allow users to indicate a preference for inclusion of
+# their names on mailing lists (electronic or physical). The absence
+# of such an attribute should be interpreted as if the attribute was
+# present with value "no-list-inclusion". This attribute should be
+# interpreted by anyone using the directory to derive mailing lists,
+# and its value respected.
+#
+# mailPreferenceOption ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX ENUMERATED {
+# no-list-inclusion(0),
+# any-list-inclusion(1), -- may be added to any lists
+# professional-list-inclusion(2)
+# -- may be added to lists
+# -- which the list provider
+# -- views as related to the
+# -- users professional inter-
+# -- ests, perhaps evaluated
+# -- from the business of the
+# -- organisation or keywords
+# -- in the entry.
+# }
+# ::= {pilotAttributeType 47}
+#
+attributetype ( 0.9.2342.19200300.100.1.47
+ NAME 'mailPreferenceOption'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
+
+# 9.3.38. Building Name
+#
+# The Building Name attribute type specifies the name of the building
+# where an organisation or organisational unit is based.
+#
+# buildingName ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-building-name))
+# ::= {pilotAttributeType 48}
+#
+attributetype ( 0.9.2342.19200300.100.1.48 NAME 'buildingName'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+
+# 9.3.39. DSA Quality
+#
+# The DSA Quality attribute type specifies the purported quality of a
+# DSA. It allows a DSA manager to indicate the expected level of
+# availability of the DSA. See [8] for details of the syntax.
+#
+# dSAQuality ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX DSAQualitySyntax
+# SINGLE VALUE
+# ::= {pilotAttributeType 49}
+#
+attributetype ( 0.9.2342.19200300.100.1.49 NAME 'dSAQuality'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.19 SINGLE-VALUE )
+
+# 9.3.40. Single Level Quality
+#
+# The Single Level Quality attribute type specifies the purported data
+# quality at the level immediately below in the DIT. See [8] for
+# details of the syntax.
+#
+# singleLevelQuality ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX DataQualitySyntax
+# SINGLE VALUE
+# ::= {pilotAttributeType 50}
+#
+attributetype ( 0.9.2342.19200300.100.1.50 NAME 'singleLevelQuality'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.13 SINGLE-VALUE )
+
+# 9.3.41. Subtree Minimum Quality
+#
+# The Subtree Minimum Quality attribute type specifies the purported
+# minimum data quality for a DIT subtree. See [8] for more discussion
+# and details of the syntax.
+#
+# subtreeMinimumQuality ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX DataQualitySyntax
+# SINGLE VALUE
+# -- Defaults to singleLevelQuality
+# ::= {pilotAttributeType 51}
+#
+attributetype ( 0.9.2342.19200300.100.1.51 NAME 'subtreeMinimumQuality'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.13 SINGLE-VALUE )
+
+# 9.3.42. Subtree Maximum Quality
+#
+# The Subtree Maximum Quality attribute type specifies the purported
+# maximum data quality for a DIT subtree. See [8] for more discussion
+# and details of the syntax.
+#
+# subtreeMaximumQuality ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX DataQualitySyntax
+# SINGLE VALUE
+# -- Defaults to singleLevelQuality
+# ::= {pilotAttributeType 52}
+#
+attributetype ( 0.9.2342.19200300.100.1.52 NAME 'subtreeMaximumQuality'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.13 SINGLE-VALUE )
+
+# 9.3.43. Personal Signature
+#
+# The Personal Signature attribute type allows for a representation of
+# a person's signature. This should be encoded in G3 fax as explained
+# in recommendation T.4, with an ASN.1 wrapper to make it compatible
+# with an X.400 BodyPart as defined in X.420.
+#
+# IMPORT G3FacsimileBodyPart FROM { mhs-motis ipms modules
+# information-objects }
+#
+# personalSignature ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# CHOICE {
+# g3-facsimile [3] G3FacsimileBodyPart
+# }
+# (SIZE (1 .. ub-personal-signature))
+# ::= {pilotAttributeType 53}
+#
+attributetype ( 0.9.2342.19200300.100.1.53 NAME 'personalSignature'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.23 )
+
+# 9.3.44. DIT Redirect
+#
+# The DIT Redirect attribute type is used to indicate that the object
+# described by one entry now has a newer entry in the DIT. The entry
+# containing the redirection attribute should be expired after a
+# suitable grace period. This attribute may be used when an individual
+# changes his/her place of work, and thus acquires a new organisational
+# DN.
+#
+# dITRedirect ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# distinguishedNameSyntax
+# ::= {pilotAttributeType 54}
+#
+attributetype ( 0.9.2342.19200300.100.1.54 NAME 'dITRedirect'
+ EQUALITY distinguishedNameMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )
+
+# 9.3.45. Audio
+#
+# The Audio attribute type allows the storing of sounds in the
+# Directory. The attribute uses a u-law encoded sound file as used by
+# the "play" utility on a Sun 4. This is an interim format.
+#
+# audio ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# Audio
+# (SIZE (1 .. ub-audio))
+# ::= {pilotAttributeType 55}
+#
+attributetype ( 0.9.2342.19200300.100.1.55 NAME 'audio'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.4{25000} )
+
+# 9.3.46. Publisher of Document
+#
+#
+# The Publisher of Document attribute is the person and/or organization
+# that published a document.
+#
+# documentPublisher ATTRIBUTE
+# WITH ATTRIBUTE SYNTAX caseIgnoreStringSyntax
+# ::= {pilotAttributeType 56}
+#
+attributetype ( 0.9.2342.19200300.100.1.56 NAME 'documentPublisher'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+# 9.4. Generally useful syntaxes
+#
+# caseIgnoreIA5StringSyntax ATTRIBUTE-SYNTAX
+# IA5String
+# MATCHES FOR EQUALITY SUBSTRINGS
+#
+# iA5StringSyntax ATTRIBUTE-SYNTAX
+# IA5String
+# MATCHES FOR EQUALITY SUBSTRINGS
+#
+#
+# -- Syntaxes to support the DNS attributes
+#
+# DNSRecordSyntax ATTRIBUTE-SYNTAX
+# IA5String
+# MATCHES FOR EQUALITY
+#
+#
+# NRSInformationSyntax ATTRIBUTE-SYNTAX
+# NRSInformation
+# MATCHES FOR EQUALITY
+#
+#
+# NRSInformation ::= SET {
+# [0] Context,
+# [1] Address-space-id,
+# routes [2] SEQUENCE OF SEQUENCE {
+# Route-cost,
+# Addressing-info }
+# }
+#
+#
+# 9.5. Upper bounds on length of attribute values
+#
+#
+# ub-document-identifier INTEGER ::= 256
+#
+# ub-document-location INTEGER ::= 256
+#
+# ub-document-title INTEGER ::= 256
+#
+# ub-document-version INTEGER ::= 256
+#
+# ub-favourite-drink INTEGER ::= 256
+#
+# ub-host INTEGER ::= 256
+#
+# ub-information INTEGER ::= 2048
+#
+# ub-unique-identifier INTEGER ::= 256
+#
+# ub-personal-title INTEGER ::= 256
+#
+# ub-photo INTEGER ::= 250000
+#
+# ub-rfc822-mailbox INTEGER ::= 256
+#
+# ub-room-number INTEGER ::= 256
+#
+# ub-text-or-address INTEGER ::= 256
+#
+# ub-user-class INTEGER ::= 256
+#
+# ub-user-identifier INTEGER ::= 256
+#
+# ub-organizational-status INTEGER ::= 256
+#
+# ub-janet-mailbox INTEGER ::= 256
+#
+# ub-building-name INTEGER ::= 256
+#
+# ub-personal-signature ::= 50000
+#
+# ub-audio INTEGER ::= 250000
+#
+
+# [back to 8]
+# 8. Object Classes
+#
+# 8.1. X.500 standard object classes
+#
+# A number of generally useful object classes are defined in X.521, and
+# these are supported. Refer to that document for descriptions of the
+# suggested usage of these object classes. The ASN.1 for these object
+# classes is reproduced for completeness in Appendix C.
+#
+# 8.2. X.400 standard object classes
+#
+# A number of object classes defined in X.400 are supported. Refer to
+# X.402 for descriptions of the usage of these object classes. The
+# ASN.1 for these object classes is reproduced for completeness in
+# Appendix C.
+#
+# 8.3. COSINE/Internet object classes
+#
+# This section attempts to fuse together the object classes designed
+# for use in the COSINE and Internet pilot activities. Descriptions
+# are given of the suggested usage of these object classes. The ASN.1
+# for these object classes is also reproduced in Appendix C.
+#
+# 8.3.1. Pilot Object
+#
+# The PilotObject object class is used as a sub-class to allow some
+# common, useful attributes to be assigned to entries of all other
+# object classes.
+#
+# pilotObject OBJECT-CLASS
+# SUBCLASS OF top
+# MAY CONTAIN {
+# info,
+# photo,
+# manager,
+# uniqueIdentifier,
+# lastModifiedTime,
+# lastModifiedBy,
+# dITRedirect,
+# audio}
+# ::= {pilotObjectClass 3}
+#
+#objectclass ( 0.9.2342.19200300.100.4.3 NAME 'pilotObject'
+# DESC 'RFC1274: pilot object'
+# SUP top AUXILIARY
+# MAY ( info $ photo $ manager $ uniqueIdentifier $
+# lastModifiedTime $ lastModifiedBy $ dITRedirect $ audio )
+# )
+
+# 8.3.2. Pilot Person
+#
+# The PilotPerson object class is used as a sub-class of person, to
+# allow the use of a number of additional attributes to be assigned to
+# entries of object class person.
+#
+# pilotPerson OBJECT-CLASS
+# SUBCLASS OF person
+# MAY CONTAIN {
+# userid,
+# textEncodedORAddress,
+# rfc822Mailbox,
+# favouriteDrink,
+# roomNumber,
+# userClass,
+# homeTelephoneNumber,
+# homePostalAddress,
+# secretary,
+# personalTitle,
+# preferredDeliveryMethod,
+# businessCategory,
+# janetMailbox,
+# otherMailbox,
+# mobileTelephoneNumber,
+# pagerTelephoneNumber,
+# organizationalStatus,
+# mailPreferenceOption,
+# personalSignature}
+# ::= {pilotObjectClass 4}
+#
+objectclass ( 0.9.2342.19200300.100.4.4
+ NAME ( 'pilotPerson' 'newPilotPerson' )
+ SUP person STRUCTURAL
+ MAY ( userid $ textEncodedORAddress $ rfc822Mailbox $
+ favouriteDrink $ roomNumber $ userClass $
+ homeTelephoneNumber $ homePostalAddress $ secretary $
+ personalTitle $ preferredDeliveryMethod $ businessCategory $
+ janetMailbox $ otherMailbox $ mobileTelephoneNumber $
+ pagerTelephoneNumber $ organizationalStatus $
+ mailPreferenceOption $ personalSignature )
+ )
+
+# 8.3.3. Account
+#
+# The Account object class is used to define entries representing
+# computer accounts. The userid attribute should be used for naming
+# entries of this object class.
+#
+# account OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# userid}
+# MAY CONTAIN {
+# description,
+# seeAlso,
+# localityName,
+# organizationName,
+# organizationalUnitName,
+# host}
+# ::= {pilotObjectClass 5}
+#
+objectclass ( 0.9.2342.19200300.100.4.5 NAME 'account'
+ SUP top STRUCTURAL
+ MUST userid
+ MAY ( description $ seeAlso $ localityName $
+ organizationName $ organizationalUnitName $ host )
+ )
+
+# 8.3.4. Document
+#
+# The Document object class is used to define entries which represent
+# documents.
+#
+# document OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# documentIdentifier}
+# MAY CONTAIN {
+# commonName,
+# description,
+# seeAlso,
+# localityName,
+# organizationName,
+# organizationalUnitName,
+# documentTitle,
+# documentVersion,
+# documentAuthor,
+# documentLocation,
+# documentPublisher}
+# ::= {pilotObjectClass 6}
+#
+objectclass ( 0.9.2342.19200300.100.4.6 NAME 'document'
+ SUP top STRUCTURAL
+ MUST documentIdentifier
+ MAY ( commonName $ description $ seeAlso $ localityName $
+ organizationName $ organizationalUnitName $
+ documentTitle $ documentVersion $ documentAuthor $
+ documentLocation $ documentPublisher )
+ )
+
+# 8.3.5. Room
+#
+# The Room object class is used to define entries representing rooms.
+# The commonName attribute should be used for naming pentries of this
+# object class.
+#
+# room OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# commonName}
+# MAY CONTAIN {
+# roomNumber,
+# description,
+# seeAlso,
+# telephoneNumber}
+# ::= {pilotObjectClass 7}
+#
+objectclass ( 0.9.2342.19200300.100.4.7 NAME 'room'
+ SUP top STRUCTURAL
+ MUST commonName
+ MAY ( roomNumber $ description $ seeAlso $ telephoneNumber )
+ )
+
+# 8.3.6. Document Series
+#
+# The Document Series object class is used to define an entry which
+# represents a series of documents (e.g., The Request For Comments
+# papers).
+#
+# documentSeries OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# commonName}
+# MAY CONTAIN {
+# description,
+# seeAlso,
+# telephoneNumber,
+# localityName,
+# organizationName,
+# organizationalUnitName}
+# ::= {pilotObjectClass 9}
+#
+objectclass ( 0.9.2342.19200300.100.4.9 NAME 'documentSeries'
+ SUP top STRUCTURAL
+ MUST commonName
+ MAY ( description $ seeAlso $ telephonenumber $
+ localityName $ organizationName $ organizationalUnitName )
+ )
+
+# 8.3.7. Domain
+#
+# The Domain object class is used to define entries which represent DNS
+# or NRS domains. The domainComponent attribute should be used for
+# naming entries of this object class. The usage of this object class
+# is described in more detail in [3].
+#
+# domain OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# domainComponent}
+# MAY CONTAIN {
+# associatedName,
+# organizationName,
+# organizationalAttributeSet}
+# ::= {pilotObjectClass 13}
+#
+objectclass ( 0.9.2342.19200300.100.4.13 NAME 'domain'
+ SUP top STRUCTURAL
+ MUST domainComponent
+ MAY ( associatedName $ organizationName $ description $
+ businessCategory $ seeAlso $ searchGuide $ userPassword $
+ localityName $ stateOrProvinceName $ streetAddress $
+ physicalDeliveryOfficeName $ postalAddress $ postalCode $
+ postOfficeBox $ streetAddress $
+ facsimileTelephoneNumber $ internationalISDNNumber $
+ telephoneNumber $ teletexTerminalIdentifier $ telexNumber $
+ preferredDeliveryMethod $ destinationIndicator $
+ registeredAddress $ x121Address )
+ )
+
+# 8.3.8. RFC822 Local Part
+#
+# The RFC822 Local Part object class is used to define entries which
+# represent the local part of RFC822 mail addresses. This treats this
+# part of an RFC822 address as a domain. The usage of this object
+# class is described in more detail in [3].
+#
+# rFC822localPart OBJECT-CLASS
+# SUBCLASS OF domain
+# MAY CONTAIN {
+# commonName,
+# surname,
+# description,
+# seeAlso,
+# telephoneNumber,
+# postalAttributeSet,
+# telecommunicationAttributeSet}
+# ::= {pilotObjectClass 14}
+#
+objectclass ( 0.9.2342.19200300.100.4.14 NAME 'RFC822localPart'
+ SUP domain STRUCTURAL
+ MAY ( commonName $ surname $ description $ seeAlso $ telephonenumber $
+ physicalDeliveryOfficeName $ postalAddress $ postalCode $
+ postOfficeBox $ streetAddress $
+ facsimileTelephoneNumber $ internationalISDNNumber $
+ telephoneNumber $ teletexTerminalIdentifier $
+ telexNumber $ preferredDeliveryMethod $ destinationIndicator $
+ registeredAddress $ x121Address )
+ )
+
+# 8.3.9. DNS Domain
+#
+# The DNS Domain (Domain NameServer) object class is used to define
+# entries for DNS domains. The usage of this object class is described
+# in more detail in [3].
+#
+# dNSDomain OBJECT-CLASS
+# SUBCLASS OF domain
+# MAY CONTAIN {
+# ARecord,
+# MDRecord,
+# MXRecord,
+# NSRecord,
+# SOARecord,
+# CNAMERecord}
+# ::= {pilotObjectClass 15}
+#
+objectclass ( 0.9.2342.19200300.100.4.15 NAME 'dNSDomain'
+ SUP domain STRUCTURAL
+ MAY ( ARecord $ MDRecord $ MXRecord $ NSRecord $
+ SOARecord $ CNAMERecord )
+ )
+
+# 8.3.10. Domain Related Object
+#
+# The Domain Related Object object class is used to define entries
+# which represent DNS/NRS domains which are "equivalent" to an X.500
+# domain: e.g., an organisation or organisational unit. The usage of
+# this object class is described in more detail in [3].
+#
+# domainRelatedObject OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# associatedDomain}
+# ::= {pilotObjectClass 17}
+#
+objectclass ( 0.9.2342.19200300.100.4.17 NAME 'domainRelatedObject'
+ SUP top AUXILIARY
+ MUST associatedDomain )
+
+# 8.3.11. Friendly Country
+#
+# The Friendly Country object class is used to define country entries
+# in the DIT. The object class is used to allow friendlier naming of
+# countries than that allowed by the object class country. The naming
+# attribute of object class country, countryName, has to be a 2 letter
+# string defined in ISO 3166.
+#
+# friendlyCountry OBJECT-CLASS
+# SUBCLASS OF country
+# MUST CONTAIN {
+# friendlyCountryName}
+# ::= {pilotObjectClass 18}
+#
+objectclass ( 0.9.2342.19200300.100.4.18 NAME 'friendlyCountry'
+ SUP country STRUCTURAL
+ MUST friendlyCountryName )
+
+# 8.3.12. Simple Security Object
+#
+# The Simple Security Object object class is used to allow an entry to
+# have a userPassword attribute when an entry's principal object
+# classes do not allow userPassword as an attribute type.
+#
+# simpleSecurityObject OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# userPassword }
+# ::= {pilotObjectClass 19}
+#
+## (in core.schema)
+## objectclass ( 0.9.2342.19200300.100.4.19 NAME 'simpleSecurityObject'
+## SUP top AUXILIARY
+## MUST userPassword )
+
+# 8.3.13. Pilot Organization
+#
+# The PilotOrganization object class is used as a sub-class of
+# organization and organizationalUnit to allow a number of additional
+# attributes to be assigned to entries of object classes organization
+# and organizationalUnit.
+#
+# pilotOrganization OBJECT-CLASS
+# SUBCLASS OF organization, organizationalUnit
+# MAY CONTAIN {
+# buildingName}
+# ::= {pilotObjectClass 20}
+#
+objectclass ( 0.9.2342.19200300.100.4.20 NAME 'pilotOrganization'
+ SUP ( organization $ organizationalUnit ) STRUCTURAL
+ MAY buildingName )
+
+# 8.3.14. Pilot DSA
+#
+# The PilotDSA object class is used as a sub-class of the dsa object
+# class to allow additional attributes to be assigned to entries for
+# DSAs.
+#
+# pilotDSA OBJECT-CLASS
+# SUBCLASS OF dsa
+# MUST CONTAIN {
+# dSAQuality}
+# ::= {pilotObjectClass 21}
+#
+objectclass ( 0.9.2342.19200300.100.4.21 NAME 'pilotDSA'
+ SUP dsa STRUCTURAL
+ MAY dSAQuality )
+
+# 8.3.15. Quality Labelled Data
+#
+# The Quality Labelled Data object class is used to allow the
+# assignment of the data quality attributes to subtrees in the DIT.
+#
+# See [8] for more details.
+#
+# qualityLabelledData OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# dSAQuality}
+# MAY CONTAIN {
+# subtreeMinimumQuality,
+# subtreeMaximumQuality}
+# ::= {pilotObjectClass 22}
+objectclass ( 0.9.2342.19200300.100.4.22 NAME 'qualityLabelledData'
+ SUP top AUXILIARY
+ MUST dsaQuality
+ MAY ( subtreeMinimumQuality $ subtreeMaximumQuality )
+ )
+
+
+# References
+#
+# [1] CCITT/ISO, "X.500, The Directory - overview of concepts,
+# models and services, CCITT /ISO IS 9594.
+#
+# [2] Kille, S., "The THORN and RARE X.500 Naming Architecture, in
+# University College London, Department of Computer Science
+# Research Note 89/48, May 1989.
+#
+# [3] Kille, S., "X.500 and Domains", RFC 1279, University College
+# London, November 1991.
+#
+# [4] Rose, M., "PSI/NYSERNet White Pages Pilot Project: Status
+# Report", Technical Report 90-09-10-1, published by NYSERNet
+# Inc, 1990.
+#
+# [5] Craigie, J., "UK Academic Community Directory Service Pilot
+# Project, pp. 305-310 in Computer Networks and ISDN Systems
+# 17 (1989), published by North Holland.
+#
+# [6] Mockapetris, P., "Domain Names - Concepts and Facilities",
+# RFC 1034, USC/Information Sciences Institute, November 1987.
+#
+# [7] Mockapetris, P., "Domain Names - Implementation and
+# Specification, RFC 1035, USC/Information Sciences Institute,
+# November 1987.
+#
+# [8] Kille, S., "Handling QOS (Quality of service) in the
+# Directory," publication in process, March 1991.
+#
+#
+# APPENDIX C - Summary of all Object Classes and Attribute Types
+#
+# -- Some Important Object Identifiers
+#
+# data OBJECT IDENTIFIER ::= {ccitt 9}
+# pss OBJECT IDENTIFIER ::= {data 2342}
+# ucl OBJECT IDENTIFIER ::= {pss 19200300}
+# pilot OBJECT IDENTIFIER ::= {ucl 100}
+#
+# pilotAttributeType OBJECT IDENTIFIER ::= {pilot 1}
+# pilotAttributeSyntax OBJECT IDENTIFIER ::= {pilot 3}
+# pilotObjectClass OBJECT IDENTIFIER ::= {pilot 4}
+# pilotGroups OBJECT IDENTIFIER ::= {pilot 10}
+#
+# iA5StringSyntax OBJECT IDENTIFIER ::= {pilotAttributeSyntax 4}
+# caseIgnoreIA5StringSyntax OBJECT IDENTIFIER ::=
+# {pilotAttributeSyntax 5}
+#
+# -- Standard Object Classes
+#
+# top OBJECT-CLASS
+# MUST CONTAIN {
+# objectClass}
+# ::= {objectClass 0}
+#
+#
+# alias OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# aliasedObjectName}
+# ::= {objectClass 1}
+#
+#
+# country OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# countryName}
+# MAY CONTAIN {
+# description,
+# searchGuide}
+# ::= {objectClass 2}
+#
+#
+# locality OBJECT-CLASS
+# SUBCLASS OF top
+# MAY CONTAIN {
+# description,
+# localityName,
+# stateOrProvinceName,
+# searchGuide,
+# seeAlso,
+# streetAddress}
+# ::= {objectClass 3}
+#
+#
+# organization OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# organizationName}
+# MAY CONTAIN {
+# organizationalAttributeSet}
+# ::= {objectClass 4}
+#
+#
+# organizationalUnit OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# organizationalUnitName}
+# MAY CONTAIN {
+# organizationalAttributeSet}
+# ::= {objectClass 5}
+#
+#
+# person OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# commonName,
+# surname}
+# MAY CONTAIN {
+# description,
+# seeAlso,
+# telephoneNumber,
+# userPassword}
+# ::= {objectClass 6}
+#
+#
+# organizationalPerson OBJECT-CLASS
+# SUBCLASS OF person
+# MAY CONTAIN {
+# localeAttributeSet,
+# organizationalUnitName,
+# postalAttributeSet,
+# telecommunicationAttributeSet,
+# title}
+# ::= {objectClass 7}
+#
+#
+# organizationalRole OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# commonName}
+# MAY CONTAIN {
+# description,
+# localeAttributeSet,
+# organizationalUnitName,
+# postalAttributeSet,
+# preferredDeliveryMethod,
+# roleOccupant,
+# seeAlso,
+# telecommunicationAttributeSet}
+# ::= {objectClass 8}
+#
+#
+# groupOfNames OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# commonName,
+# member}
+# MAY CONTAIN {
+# description,
+# organizationName,
+# organizationalUnitName,
+# owner,
+# seeAlso,
+# businessCategory}
+# ::= {objectClass 9}
+#
+#
+# residentialPerson OBJECT-CLASS
+# SUBCLASS OF person
+# MUST CONTAIN {
+# localityName}
+# MAY CONTAIN {
+# localeAttributeSet,
+# postalAttributeSet,
+# preferredDeliveryMethod,
+# telecommunicationAttributeSet,
+# businessCategory}
+# ::= {objectClass 10}
+#
+#
+# applicationProcess OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# commonName}
+# MAY CONTAIN {
+# description,
+# localityName,
+# organizationalUnitName,
+# seeAlso}
+# ::= {objectClass 11}
+#
+#
+# applicationEntity OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# commonName,
+# presentationAddress}
+# MAY CONTAIN {
+# description,
+# localityName,
+# organizationName,
+# organizationalUnitName,
+# seeAlso,
+# supportedApplicationContext}
+# ::= {objectClass 12}
+#
+#
+# dSA OBJECT-CLASS
+# SUBCLASS OF applicationEntity
+# MAY CONTAIN {
+# knowledgeInformation}
+# ::= {objectClass 13}
+#
+#
+# device OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# commonName}
+# MAY CONTAIN {
+# description,
+# localityName,
+# organizationName,
+# organizationalUnitName,
+# owner,
+# seeAlso,
+# serialNumber}
+# ::= {objectClass 14}
+#
+#
+# strongAuthenticationUser OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# userCertificate}
+# ::= {objectClass 15}
+#
+#
+# certificationAuthority OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# cACertificate,
+# certificateRevocationList,
+# authorityRevocationList}
+# MAY CONTAIN {
+# crossCertificatePair}
+# ::= {objectClass 16}
+#
+# -- Standard MHS Object Classes
+#
+# mhsDistributionList OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# commonName,
+# mhsDLSubmitPermissions,
+# mhsORAddresses}
+# MAY CONTAIN {
+# description,
+# organizationName,
+# organizationalUnitName,
+# owner,
+# seeAlso,
+# mhsDeliverableContentTypes,
+# mhsdeliverableEits,
+# mhsDLMembers,
+# mhsPreferredDeliveryMethods}
+# ::= {mhsObjectClass 0}
+#
+#
+# mhsMessageStore OBJECT-CLASS
+# SUBCLASS OF applicationEntity
+# MAY CONTAIN {
+# description,
+# owner,
+# mhsSupportedOptionalAttributes,
+# mhsSupportedAutomaticActions,
+# mhsSupportedContentTypes}
+# ::= {mhsObjectClass 1}
+#
+#
+# mhsMessageTransferAgent OBJECT-CLASS
+# SUBCLASS OF applicationEntity
+# MAY CONTAIN {
+# description,
+# owner,
+# mhsDeliverableContentLength}
+# ::= {mhsObjectClass 2}
+#
+#
+# mhsOrganizationalUser OBJECT-CLASS
+# SUBCLASS OF organizationalPerson
+# MUST CONTAIN {
+# mhsORAddresses}
+# MAY CONTAIN {
+# mhsDeliverableContentLength,
+# mhsDeliverableContentTypes,
+# mhsDeliverableEits,
+# mhsMessageStoreName,
+# mhsPreferredDeliveryMethods }
+# ::= {mhsObjectClass 3}
+#
+#
+# mhsResidentialUser OBJECT-CLASS
+# SUBCLASS OF residentialPerson
+# MUST CONTAIN {
+# mhsORAddresses}
+# MAY CONTAIN {
+# mhsDeliverableContentLength,
+# mhsDeliverableContentTypes,
+# mhsDeliverableEits,
+# mhsMessageStoreName,
+# mhsPreferredDeliveryMethods }
+# ::= {mhsObjectClass 4}
+#
+#
+# mhsUserAgent OBJECT-CLASS
+# SUBCLASS OF applicationEntity
+# MAY CONTAIN {
+# mhsDeliverableContentLength,
+# mhsDeliverableContentTypes,
+# mhsDeliverableEits,
+# mhsORAddresses,
+# owner}
+# ::= {mhsObjectClass 5}
+#
+#
+#
+#
+# -- Pilot Object Classes
+#
+# pilotObject OBJECT-CLASS
+# SUBCLASS OF top
+# MAY CONTAIN {
+# info,
+# photo,
+# manager,
+# uniqueIdentifier,
+# lastModifiedTime,
+# lastModifiedBy,
+# dITRedirect,
+# audio}
+# ::= {pilotObjectClass 3}
+# pilotPerson OBJECT-CLASS
+# SUBCLASS OF person
+# MAY CONTAIN {
+# userid,
+# textEncodedORAddress,
+# rfc822Mailbox,
+# favouriteDrink,
+# roomNumber,
+# userClass,
+# homeTelephoneNumber,
+# homePostalAddress,
+# secretary,
+# personalTitle,
+# preferredDeliveryMethod,
+# businessCategory,
+# janetMailbox,
+# otherMailbox,
+# mobileTelephoneNumber,
+# pagerTelephoneNumber,
+# organizationalStatus,
+# mailPreferenceOption,
+# personalSignature}
+# ::= {pilotObjectClass 4}
+#
+#
+# account OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# userid}
+# MAY CONTAIN {
+# description,
+# seeAlso,
+# localityName,
+# organizationName,
+# organizationalUnitName,
+# host}
+# ::= {pilotObjectClass 5}
+#
+#
+# document OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# documentIdentifier}
+# MAY CONTAIN {
+# commonName,
+# description,
+# seeAlso,
+# localityName,
+# organizationName,
+# organizationalUnitName,
+# documentTitle,
+# documentVersion,
+# documentAuthor,
+# documentLocation,
+# documentPublisher}
+# ::= {pilotObjectClass 6}
+#
+#
+# room OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# commonName}
+# MAY CONTAIN {
+# roomNumber,
+# description,
+# seeAlso,
+# telephoneNumber}
+# ::= {pilotObjectClass 7}
+#
+#
+# documentSeries OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# commonName}
+# MAY CONTAIN {
+# description,
+# seeAlso,
+# telephoneNumber,
+# localityName,
+# organizationName,
+# organizationalUnitName}
+# ::= {pilotObjectClass 9}
+#
+#
+# domain OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# domainComponent}
+# MAY CONTAIN {
+# associatedName,
+# organizationName,
+# organizationalAttributeSet}
+# ::= {pilotObjectClass 13}
+#
+#
+# rFC822localPart OBJECT-CLASS
+# SUBCLASS OF domain
+# MAY CONTAIN {
+# commonName,
+# surname,
+# description,
+# seeAlso,
+# telephoneNumber,
+# postalAttributeSet,
+# telecommunicationAttributeSet}
+# ::= {pilotObjectClass 14}
+#
+#
+# dNSDomain OBJECT-CLASS
+# SUBCLASS OF domain
+# MAY CONTAIN {
+# ARecord,
+# MDRecord,
+# MXRecord,
+# NSRecord,
+# SOARecord,
+# CNAMERecord}
+# ::= {pilotObjectClass 15}
+#
+#
+# domainRelatedObject OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# associatedDomain}
+# ::= {pilotObjectClass 17}
+#
+#
+# friendlyCountry OBJECT-CLASS
+# SUBCLASS OF country
+# MUST CONTAIN {
+# friendlyCountryName}
+# ::= {pilotObjectClass 18}
+#
+#
+# simpleSecurityObject OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# userPassword }
+# ::= {pilotObjectClass 19}
+#
+#
+# pilotOrganization OBJECT-CLASS
+# SUBCLASS OF organization, organizationalUnit
+# MAY CONTAIN {
+# buildingName}
+# ::= {pilotObjectClass 20}
+#
+#
+# pilotDSA OBJECT-CLASS
+# SUBCLASS OF dsa
+# MUST CONTAIN {
+# dSAQuality}
+# ::= {pilotObjectClass 21}
+#
+#
+# qualityLabelledData OBJECT-CLASS
+# SUBCLASS OF top
+# MUST CONTAIN {
+# dSAQuality}
+# MAY CONTAIN {
+# subtreeMinimumQuality,
+# subtreeMaximumQuality}
+# ::= {pilotObjectClass 22}
+#
+#
+#
+#
+# -- Standard Attribute Types
+#
+# objectClass ObjectClass
+# ::= {attributeType 0}
+#
+#
+# aliasedObjectName AliasedObjectName
+# ::= {attributeType 1}
+#
+#
+# knowledgeInformation ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX caseIgnoreString
+# ::= {attributeType 2}
+#
+#
+# commonName ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX caseIgnoreStringSyntax
+# (SIZE (1..ub-common-name))
+# ::= {attributeType 3}
+#
+#
+# surname ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX caseIgnoreStringSyntax
+# (SIZE (1..ub-surname))
+# ::= {attributeType 4}
+#
+#
+# serialNumber ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX printableStringSyntax
+# (SIZE (1..ub-serial-number))
+# ::= {attributeType 5}
+#
+#
+# countryName ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX PrintableString
+# (SIZE (1..ub-country-code))
+# SINGLE VALUE
+# ::= {attributeType 6}
+#
+#
+# localityName ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX caseIgnoreStringSyntax
+# (SIZE (1..ub-locality-name))
+# ::= {attributeType 7}
+#
+#
+# stateOrProvinceName ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX caseIgnoreStringSyntax
+# (SIZE (1..ub-state-name))
+# ::= {attributeType 8}
+#
+#
+# streetAddress ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX caseIgnoreStringSyntax
+# (SIZE (1..ub-street-address))
+# ::= {attributeType 9}
+#
+#
+# organizationName ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX caseIgnoreStringSyntax
+# (SIZE (1..ub-organization-name))
+# ::= {attributeType 10}
+#
+#
+# organizationalUnitName ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX caseIgnoreStringSyntax
+# (SIZE (1..ub-organizational-unit-name))
+# ::= {attributeType 11}
+#
+#
+# title ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX caseIgnoreStringSyntax
+# (SIZE (1..ub-title))
+# ::= {attributeType 12}
+#
+#
+# description ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX caseIgnoreStringSyntax
+# (SIZE (1..ub-description))
+# ::= {attributeType 13}
+#
+#
+# searchGuide ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX Guide
+# ::= {attributeType 14}
+#
+#
+# businessCategory ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX caseIgnoreStringSyntax
+# (SIZE (1..ub-business-category))
+# ::= {attributeType 15}
+#
+#
+# postalAddress ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX PostalAddress
+# MATCHES FOR EQUALITY
+# ::= {attributeType 16}
+#
+#
+# postalCode ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX caseIgnoreStringSyntax
+# (SIZE (1..ub-postal-code))
+# ::= {attributeType 17}
+#
+#
+# postOfficeBox ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX caseIgnoreStringSyntax
+# (SIZE (1..ub-post-office-box))
+# ::= {attributeType 18}
+#
+#
+# physicalDeliveryOfficeName ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX caseIgnoreStringSyntax
+# (SIZE (1..ub-physical-office-name))
+# ::= {attributeType 19}
+#
+#
+# telephoneNumber ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX telephoneNumberSyntax
+# (SIZE (1..ub-telephone-number))
+# ::= {attributeType 20}
+#
+#
+# telexNumber ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX TelexNumber
+# (SIZE (1..ub-telex))
+# ::= {attributeType 21}
+#
+#
+# teletexTerminalIdentifier ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX TeletexTerminalIdentifier
+# (SIZE (1..ub-teletex-terminal-id))
+# ::= {attributeType 22}
+#
+#
+# facsimileTelephoneNumber ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX FacsimileTelephoneNumber
+# ::= {attributeType 23}
+#
+#
+# x121Address ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX NumericString
+# (SIZE (1..ub-x121-address))
+# ::= {attributeType 24}
+#
+#
+# internationaliSDNNumber ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX NumericString
+# (SIZE (1..ub-isdn-address))
+# ::= {attributeType 25}
+#
+#
+# registeredAddress ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX PostalAddress
+# ::= {attributeType 26}
+#
+#
+# destinationIndicator ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX PrintableString
+# (SIZE (1..ub-destination-indicator))
+# MATCHES FOR EQUALITY SUBSTRINGS
+# ::= {attributeType 27}
+#
+#
+# preferredDeliveryMethod ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX deliveryMethod
+# ::= {attributeType 28}
+#
+#
+# presentationAddress ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX PresentationAddress
+# MATCHES FOR EQUALITY
+# ::= {attributeType 29}
+#
+#
+# supportedApplicationContext ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX objectIdentifierSyntax
+# ::= {attributeType 30}
+#
+#
+# member ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX distinguishedNameSyntax
+# ::= {attributeType 31}
+#
+#
+# owner ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX distinguishedNameSyntax
+# ::= {attributeType 32}
+#
+#
+# roleOccupant ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX distinguishedNameSyntax
+# ::= {attributeType 33}
+#
+#
+# seeAlso ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX distinguishedNameSyntax
+# ::= {attributeType 34}
+#
+#
+# userPassword ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX Userpassword
+# ::= {attributeType 35}
+#
+#
+# userCertificate ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX UserCertificate
+# ::= {attributeType 36}
+#
+#
+# cACertificate ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX cACertificate
+# ::= {attributeType 37}
+#
+#
+# authorityRevocationList ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX AuthorityRevocationList
+# ::= {attributeType 38}
+#
+#
+# certificateRevocationList ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX CertificateRevocationList
+# ::= {attributeType 39}
+#
+#
+# crossCertificatePair ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX CrossCertificatePair
+# ::= {attributeType 40}
+#
+#
+#
+#
+# -- Standard MHS Attribute Types
+#
+# mhsDeliverableContentLength ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX integer
+# ::= {mhsAttributeType 0}
+#
+#
+# mhsDeliverableContentTypes ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX oID
+# ::= {mhsAttributeType 1}
+#
+#
+# mhsDeliverableEits ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX oID
+# ::= {mhsAttributeType 2}
+#
+#
+# mhsDLMembers ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX oRName
+# ::= {mhsAttributeType 3}
+#
+#
+# mhsDLSubmitPermissions ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX dLSubmitPermission
+# ::= {mhsAttributeType 4}
+#
+#
+# mhsMessageStoreName ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX dN
+# ::= {mhsAttributeType 5}
+#
+#
+# mhsORAddresses ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX oRAddress
+# ::= {mhsAttributeType 6}
+#
+#
+# mhsPreferredDeliveryMethods ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX deliveryMethod
+# ::= {mhsAttributeType 7}
+#
+#
+# mhsSupportedAutomaticActions ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX oID
+# ::= {mhsAttributeType 8}
+#
+#
+# mhsSupportedContentTypes ATTRIBUTE
+#
+# WITH ATTRIBUTE-SYNTAX oID
+# ::= {mhsAttributeType 9}
+#
+#
+# mhsSupportedOptionalAttributes ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX oID
+# ::= {mhsAttributeType 10}
+#
+#
+#
+#
+# -- Pilot Attribute Types
+#
+# userid ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-user-identifier))
+# ::= {pilotAttributeType 1}
+#
+#
+# textEncodedORAddress ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-text-encoded-or-address))
+# ::= {pilotAttributeType 2}
+#
+#
+# rfc822Mailbox ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreIA5StringSyntax
+# (SIZE (1 .. ub-rfc822-mailbox))
+# ::= {pilotAttributeType 3}
+#
+#
+# info ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-information))
+# ::= {pilotAttributeType 4}
+#
+#
+# favouriteDrink ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-favourite-drink))
+# ::= {pilotAttributeType 5}
+#
+#
+# roomNumber ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-room-number))
+# ::= {pilotAttributeType 6}
+#
+#
+# photo ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# CHOICE {
+# g3-facsimile [3] G3FacsimileBodyPart
+# }
+# (SIZE (1 .. ub-photo))
+# ::= {pilotAttributeType 7}
+#
+#
+# userClass ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-user-class))
+# ::= {pilotAttributeType 8}
+#
+#
+# host ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-host))
+# ::= {pilotAttributeType 9}
+#
+#
+# manager ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# distinguishedNameSyntax
+# ::= {pilotAttributeType 10}
+#
+#
+# documentIdentifier ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-document-identifier))
+# ::= {pilotAttributeType 11}
+#
+#
+# documentTitle ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-document-title))
+# ::= {pilotAttributeType 12}
+#
+#
+# documentVersion ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-document-version))
+# ::= {pilotAttributeType 13}
+#
+#
+# documentAuthor ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# distinguishedNameSyntax
+# ::= {pilotAttributeType 14}
+#
+#
+# documentLocation ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-document-location))
+# ::= {pilotAttributeType 15}
+#
+#
+# homeTelephoneNumber ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# telephoneNumberSyntax
+# ::= {pilotAttributeType 20}
+#
+#
+# secretary ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# distinguishedNameSyntax
+# ::= {pilotAttributeType 21}
+#
+#
+# otherMailbox ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# SEQUENCE {
+# mailboxType PrintableString, -- e.g. Telemail
+# mailbox IA5String -- e.g. X378:Joe
+# }
+# ::= {pilotAttributeType 22}
+#
+#
+# lastModifiedTime ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# uTCTimeSyntax
+# ::= {pilotAttributeType 23}
+#
+#
+# lastModifiedBy ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# distinguishedNameSyntax
+# ::= {pilotAttributeType 24}
+#
+#
+# domainComponent ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreIA5StringSyntax
+# SINGLE VALUE
+# ::= {pilotAttributeType 25}
+#
+#
+# aRecord ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# DNSRecordSyntax
+# ::= {pilotAttributeType 26}
+#
+#
+# mXRecord ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# DNSRecordSyntax
+# ::= {pilotAttributeType 28}
+#
+#
+# nSRecord ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# DNSRecordSyntax
+# ::= {pilotAttributeType 29}
+#
+# sOARecord ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# DNSRecordSyntax
+# ::= {pilotAttributeType 30}
+#
+#
+# cNAMERecord ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# iA5StringSyntax
+# ::= {pilotAttributeType 31}
+#
+#
+# associatedDomain ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreIA5StringSyntax
+# ::= {pilotAttributeType 37}
+#
+#
+# associatedName ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# distinguishedNameSyntax
+# ::= {pilotAttributeType 38}
+#
+#
+# homePostalAddress ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# postalAddress
+# MATCHES FOR EQUALITY
+# ::= {pilotAttributeType 39}
+#
+#
+# personalTitle ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-personal-title))
+# ::= {pilotAttributeType 40}
+#
+#
+# mobileTelephoneNumber ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# telephoneNumberSyntax
+# ::= {pilotAttributeType 41}
+#
+#
+# pagerTelephoneNumber ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# telephoneNumberSyntax
+# ::= {pilotAttributeType 42}
+#
+#
+# friendlyCountryName ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# ::= {pilotAttributeType 43}
+#
+#
+# uniqueIdentifier ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-unique-identifier))
+# ::= {pilotAttributeType 44}
+#
+#
+# organizationalStatus ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-organizational-status))
+# ::= {pilotAttributeType 45}
+#
+#
+# janetMailbox ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreIA5StringSyntax
+# (SIZE (1 .. ub-janet-mailbox))
+# ::= {pilotAttributeType 46}
+#
+#
+# mailPreferenceOption ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX ENUMERATED {
+# no-list-inclusion(0),
+# any-list-inclusion(1), -- may be added to any lists
+# professional-list-inclusion(2)
+# -- may be added to lists
+# -- which the list provider
+# -- views as related to the
+# -- users professional inter-
+# -- ests, perhaps evaluated
+# -- from the business of the
+# -- organisation or keywords
+# -- in the entry.
+# }
+# ::= {pilotAttributeType 47}
+#
+#
+# buildingName ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# caseIgnoreStringSyntax
+# (SIZE (1 .. ub-building-name))
+# ::= {pilotAttributeType 48}
+#
+#
+# dSAQuality ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX DSAQualitySyntax
+# SINGLE VALUE
+# ::= {pilotAttributeType 49}
+#
+#
+# singleLevelQuality ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX DataQualitySyntax
+# SINGLE VALUE
+#
+#
+# subtreeMinimumQuality ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX DataQualitySyntax
+# SINGLE VALUE
+# -- Defaults to singleLevelQuality
+# ::= {pilotAttributeType 51}
+#
+#
+# subtreeMaximumQuality ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX DataQualitySyntax
+# SINGLE VALUE
+# -- Defaults to singleLevelQuality
+# ::= {pilotAttributeType 52}
+#
+#
+# personalSignature ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# CHOICE {
+# g3-facsimile [3] G3FacsimileBodyPart
+# }
+# (SIZE (1 .. ub-personal-signature))
+# ::= {pilotAttributeType 53}
+#
+#
+# dITRedirect ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# distinguishedNameSyntax
+# ::= {pilotAttributeType 54}
+#
+#
+# audio ATTRIBUTE
+# WITH ATTRIBUTE-SYNTAX
+# Audio
+# (SIZE (1 .. ub-audio))
+# ::= {pilotAttributeType 55}
+#
+# documentPublisher ATTRIBUTE
+# WITH ATTRIBUTE SYNTAX caseIgnoreStringSyntax
+# ::= {pilotAttributeType 56}
+#
+#
+#
+# -- Generally useful syntaxes
+#
+#
+# caseIgnoreIA5StringSyntax ATTRIBUTE-SYNTAX
+# IA5String
+# MATCHES FOR EQUALITY SUBSTRINGS
+#
+#
+# iA5StringSyntax ATTRIBUTE-SYNTAX
+# IA5String
+# MATCHES FOR EQUALITY SUBSTRINGS
+#
+#
+# -- Syntaxes to support the DNS attributes
+#
+# DNSRecordSyntax ATTRIBUTE-SYNTAX
+# IA5String
+# MATCHES FOR EQUALITY
+#
+#
+# NRSInformationSyntax ATTRIBUTE-SYNTAX
+# NRSInformation
+# MATCHES FOR EQUALITY
+#
+#
+# NRSInformation ::= SET {
+# [0] Context,
+# [1] Address-space-id,
+# routes [2] SEQUENCE OF SEQUENCE {
+# Route-cost,
+# Addressing-info }
+# }
+#
+#
+# -- Upper bounds on length of attribute values
+#
+#
+# ub-document-identifier INTEGER ::= 256
+#
+# ub-document-location INTEGER ::= 256
+#
+# ub-document-title INTEGER ::= 256
+#
+# ub-document-version INTEGER ::= 256
+#
+# ub-favourite-drink INTEGER ::= 256
+#
+# ub-host INTEGER ::= 256
+#
+# ub-information INTEGER ::= 2048
+#
+# ub-unique-identifier INTEGER ::= 256
+#
+# ub-personal-title INTEGER ::= 256
+#
+# ub-photo INTEGER ::= 250000
+#
+# ub-rfc822-mailbox INTEGER ::= 256
+#
+# ub-room-number INTEGER ::= 256
+#
+# ub-text-or-address INTEGER ::= 256
+#
+# ub-user-class INTEGER ::= 256
+#
+# ub-user-identifier INTEGER ::= 256
+#
+# ub-organizational-status INTEGER ::= 256
+#
+# ub-janet-mailbox INTEGER ::= 256
+#
+# ub-building-name INTEGER ::= 256
+#
+# ub-personal-signature ::= 50000
+#
+# ub-audio INTEGER ::= 250000
+#
+# [remainder of memo trimmed]
+
Added: incubator/directory/eve/branches/start/src/schema/inetorgperson.schema
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/schema/inetorgperson.schema Thu Jun 24 00:06:35 2004
@@ -0,0 +1,143 @@
+# $OpenLDAP: pkg/ldap/servers/slapd/schema/inetorgperson.schema,v 1.4.2.6 2001/10/09 17:15:08 kurt Exp $
+#
+# InetOrgPerson (RFC2798)
+#
+# Depends upon
+# Definition of an X.500 Attribute Type and an Object Class to Hold
+# Uniform Resource Identifiers (URIs) [RFC2079]
+# (core.schema)
+#
+# A Summary of the X.500(96) User Schema for use with LDAPv3 [RFC2256]
+# (core.schema)
+#
+# The COSINE and Internet X.500 Schema [RFC1274] (cosine.schema)
+
+# carLicense
+# This multivalued field is used to record the values of the license or
+# registration plate associated with an individual.
+attributetype ( 2.16.840.1.113730.3.1.1
+ NAME 'carLicense'
+ DESC 'RFC2798: vehicle license or registration plate'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+# departmentNumber
+# Code for department to which a person belongs. This can also be
+# strictly numeric (e.g., 1234) or alphanumeric (e.g., ABC/123).
+attributetype ( 2.16.840.1.113730.3.1.2
+ NAME 'departmentNumber'
+ DESC 'RFC2798: identifies a department within an organization'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+# displayName
+# When displaying an entry, especially within a one-line summary list, it
+# is useful to be able to identify a name to be used. Since other attri-
+# bute types such as 'cn' are multivalued, an additional attribute type is
+# needed. Display name is defined for this purpose.
+attributetype ( 2.16.840.1.113730.3.1.241
+ NAME 'displayName'
+ DESC 'RFC2798: preferred name to be used when displaying entries'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+ SINGLE-VALUE )
+
+# employeeNumber
+# Numeric or alphanumeric identifier assigned to a person, typically based
+# on order of hire or association with an organization. Single valued.
+attributetype ( 2.16.840.1.113730.3.1.3
+ NAME 'employeeNumber'
+ DESC 'RFC2798: numerically identifies an employee within an organization'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+ SINGLE-VALUE )
+
+# employeeType
+# Used to identify the employer to employee relationship. Typical values
+# used will be "Contractor", "Employee", "Intern", "Temp", "External", and
+# "Unknown" but any value may be used.
+attributetype ( 2.16.840.1.113730.3.1.4
+ NAME 'employeeType'
+ DESC 'RFC2798: type of employment for a person'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+# jpegPhoto
+# Used to store one or more images of a person using the JPEG File
+# Interchange Format [JFIF].
+# Note that the jpegPhoto attribute type was defined for use in the
+# Internet X.500 pilots but no referencable definition for it could be
+# located.
+attributetype ( 0.9.2342.19200300.100.1.60
+ NAME 'jpegPhoto'
+ DESC 'a JPEG image'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.28 )
+
+# preferredLanguage
+# Used to indicate an individual's preferred written or spoken
+# language. This is useful for international correspondence or human-
+# computer interaction. Values for this attribute type MUST conform to
+# the definition of the Accept-Language header field defined in
+# [RFC2068] with one exception: the sequence "Accept-Language" ":"
+# should be omitted. This is a single valued attribute type.
+attributetype ( 2.16.840.1.113730.3.1.39
+ NAME 'preferredLanguage'
+ DESC 'RFC2798: preferred written or spoken language for a person'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+ SINGLE-VALUE )
+
+# userSMIMECertificate
+# A PKCS#7 [RFC2315] SignedData, where the content that is signed is
+# ignored by consumers of userSMIMECertificate values. It is
+# recommended that values have a `contentType' of data with an absent
+# `content' field. Values of this attribute contain a person's entire
+# certificate chain and an smimeCapabilities field [RFC2633] that at a
+# minimum describes their SMIME algorithm capabilities. Values for
+# this attribute are to be stored and requested in binary form, as
+# 'userSMIMECertificate;binary'. If available, this attribute is
+# preferred over the userCertificate attribute for S/MIME applications.
+## OpenLDAP note: ";binary" transfer should NOT be used as syntax is binary
+attributetype ( 2.16.840.1.113730.3.1.40
+ NAME 'userSMIMECertificate'
+ DESC 'RFC2798: PKCS#7 SignedData used to support S/MIME'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 )
+
+# userPKCS12
+# PKCS #12 [PKCS12] provides a format for exchange of personal identity
+# information. When such information is stored in a directory service,
+# the userPKCS12 attribute should be used. This attribute is to be stored
+# and requested in binary form, as 'userPKCS12;binary'. The attribute
+# values are PFX PDUs stored as binary data.
+## OpenLDAP note: ";binary" transfer should NOT be used as syntax is binary
+attributetype ( 2.16.840.1.113730.3.1.216
+ NAME 'userPKCS12'
+ DESC 'RFC2798: PKCS #12 PFX PDU for exchange of
+ personal identity information'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 )
+
+
+# inetOrgPerson
+# The inetOrgPerson represents people who are associated with an
+# organization in some way. It is a structural class and is derived
+# from the organizationalPerson which is defined in X.521 [X521].
+objectclass ( 2.16.840.1.113730.3.2.2
+ NAME 'inetOrgPerson'
+ DESC 'RFC2798: Internet Organizational Person'
+ SUP organizationalPerson
+ STRUCTURAL
+ MAY (
+ audio $ businessCategory $ carLicense $ departmentNumber $
+ displayName $ employeeNumber $ employeeType $ givenName $
+ homePhone $ homePostalAddress $ initials $ jpegPhoto $
+ labeledURI $ mail $ manager $ mobile $ o $ pager $
+ photo $ roomNumber $ secretary $ uid $ userCertificate $
+ x500uniqueIdentifier $ preferredLanguage $
+ userSMIMECertificate $ userPKCS12 )
+ )
Added: incubator/directory/eve/branches/start/src/schema/java.schema
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/schema/java.schema Thu Jun 24 00:06:35 2004
@@ -0,0 +1,388 @@
+# Java Object Schema
+# $OpenLDAP: pkg/ldap/servers/slapd/schema/java.schema,v 1.1.2.2 2000/09/13 18:16:13 kurt Exp $
+# depends upon core.schema
+
+# Network Working Group V. Ryan
+# Request for Comments: 2713 S. Seligman
+# Category: Informational R. Lee
+# Sun Microsystems, Inc.
+# October 1999
+#
+#
+# Schema for Representing Java(tm) Objects in an LDAP Directory
+#
+# Status of this Memo
+#
+# This memo provides information for the Internet community. It does
+# not specify an Internet standard of any kind. Distribution of this
+# memo is unlimited.
+#
+# Copyright Notice
+#
+# Copyright (C) The Internet Society (1999). All Rights Reserved.
+#
+# Abstract
+#
+# This document defines the schema for representing Java(tm) objects in
+# an LDAP directory [LDAPv3]. It defines schema elements to represent
+# a Java serialized object [Serial], a Java marshalled object [RMI], a
+# Java remote object [RMI], and a JNDI reference [JNDI].
+#
+
+# [trimmed]
+
+# 3 Attribute Type Definitions
+#
+# The following attribute types are defined in this document:
+#
+# javaClassName
+# javaClassNames
+# javaCodebase
+# javaSerializedData
+# javaFactory
+# javaReferenceAddress
+# javaDoc
+#
+# 3.1 javaClassName
+#
+# This attribute stores the fully qualified name of the Java object's
+# "distinguished" class or interface (for example, "java.lang.String").
+# It is a single-valued attribute. This attribute's syntax is '
+# Directory String' and its case is significant.
+#
+# ( 1.3.6.1.4.1.42.2.27.4.1.6
+# NAME 'javaClassName'
+# DESC 'Fully qualified name of distinguished Java class or
+# interface'
+# EQUALITY caseExactMatch
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+# SINGLE-VALUE
+# )
+#
+attributetype ( 1.3.6.1.4.1.42.2.27.4.1.6
+ NAME 'javaClassName'
+ DESC 'Fully qualified name of distinguished Java class or interface'
+ EQUALITY caseExactMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+ SINGLE-VALUE )
+
+# 3.2 javaCodebase
+#
+# This attribute stores the Java class definition's locations. It
+# specifies the locations from which to load the class definition for
+# the class specified by the javaClassName attribute. Each value of
+# the attribute contains an ordered list of URLs, separated by spaces.
+# For example, a value of "url1 url2 url3" means that the three
+# (possibly interdependent) URLs (url1, url2, and url3) form the
+# codebase for loading in the Java class definition.
+#
+# If the javaCodebase attribute contains more than one value, each
+# value is an independent codebase. That is, there is no relationship
+# between the URLs in one value and those in another; each value can be
+# viewed as an alternate source for loading the Java class definition.
+# See [Java] for information regarding class loading.
+#
+# This attribute's syntax is 'IA5 String' and its case is significant.
+#
+# ( 1.3.6.1.4.1.42.2.27.4.1.7
+# NAME 'javaCodebase'
+# DESC 'URL(s) specifying the location of class definition'
+# EQUALITY caseExactIA5Match
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+# )
+#
+attributetype ( 1.3.6.1.4.1.42.2.27.4.1.7
+ NAME 'javaCodebase'
+ DESC 'URL(s) specifying the location of class definition'
+ EQUALITY caseExactIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+# 3.3 javaClassNames
+#
+# This attribute stores the Java object's fully qualified class or
+# interface names (for example, "java.lang.String"). It is a
+# multivalued attribute. When more than one value is present, each is
+# the name of a class or interface, or ancestor class or interface, of
+# this object.
+#
+# This attribute's syntax is 'Directory String' and its case is
+# significant.
+#
+# ( 1.3.6.1.4.1.42.2.27.4.1.13
+# NAME 'javaClassNames'
+# DESC 'Fully qualified Java class or interface name'
+# EQUALITY caseExactMatch
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+# )
+#
+#
+attributetype ( 1.3.6.1.4.1.42.2.27.4.1.13
+ NAME 'javaClassNames'
+ DESC 'Fully qualified Java class or interface name'
+ EQUALITY caseExactMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+# 3.4 javaSerializedData
+#
+# This attribute stores the serialized form of a Java object. The
+# serialized form is described in [Serial].
+#
+# This attribute's syntax is 'Octet String'.
+#
+# ( 1.3.6.1.4.1.42.2.27.4.1.8
+# NAME 'javaSerializedData
+# DESC 'Serialized form of a Java object'
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.40
+# SINGLE-VALUE
+# )
+#
+attributetype ( 1.3.6.1.4.1.42.2.27.4.1.8
+ NAME 'javaSerializedData'
+ DESC 'Serialized form of a Java object'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.40
+ SINGLE-VALUE )
+
+# 3.5 javaFactory
+#
+# This attribute stores the fully qualified class name of the object
+# factory (for example, "com.wiz.jndi.WizObjectFactory") that can be
+# used to create an instance of the object identified by the
+# javaClassName attribute.
+#
+# This attribute's syntax is 'Directory String' and its case is
+# significant.
+#
+# ( 1.3.6.1.4.1.42.2.27.4.1.10
+# NAME 'javaFactory'
+# DESC 'Fully qualified Java class name of a JNDI object factory'
+# EQUALITY caseExactMatch
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+# SINGLE-VALUE
+# )
+#
+attributetype ( 1.3.6.1.4.1.42.2.27.4.1.10
+ NAME 'javaFactory'
+ DESC 'Fully qualified Java class name of a JNDI object factory'
+ EQUALITY caseExactMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+ SINGLE-VALUE )
+
+# 3.6 javaReferenceAddress
+#
+# This attribute represents the sequence of addresses of a JNDI
+# reference. Each of its values represents one address, a Java object
+# of type javax.naming.RefAddr. Its value is a concatenation of the
+# address type and address contents, preceded by a sequence number (the
+# order of addresses in a JNDI reference is significant). For example:
+#
+# #0#TypeA#ValA
+# #1#TypeB#ValB
+# #2#TypeC##rO0ABXNyABpq...
+#
+# In more detail, the value is encoded as follows:
+#
+# The delimiter is the first character of the value. For readability
+# the character '#' is recommended when it is not otherwise used
+# anywhere in the value, but any character may be used subject to
+# restrictions given below.
+#
+# The first delimiter is followed by the sequence number. The sequence
+# number of an address is its position in the JNDI reference, with the
+# first address being numbered 0. It is represented by its shortest
+# string form, in decimal notation.
+#
+# The sequence number is followed by a delimiter, then by the address
+# type, and then by another delimiter. If the address is of Java class
+# javax.naming.StringRefAddr, then this delimiter is followed by the
+# value of the address contents (which is a string). Otherwise, this
+# delimiter is followed immediately by another delimiter, and then by
+# the Base64 encoding of the serialized form of the entire address.
+#
+# The delimiter may be any character other than a digit or a character
+# contained in the address type. In addition, if the address contents
+# is a string, the delimiter may not be the first character of that
+# string.
+#
+# This attribute's syntax is 'Directory String' and its case is
+# significant. It can contain multiple values.
+#
+# ( 1.3.6.1.4.1.42.2.27.4.1.11
+# NAME 'javaReferenceAddress'
+# DESC 'Addresses associated with a JNDI Reference'
+# EQUALITY caseExactMatch
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+# )
+#
+attributetype ( 1.3.6.1.4.1.42.2.27.4.1.11
+ NAME 'javaReferenceAddress'
+ DESC 'Addresses associated with a JNDI Reference'
+ EQUALITY caseExactMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+# 3.7 javaDoc
+#
+# This attribute stores a pointer to the Java documentation for the
+# class. It's value is a URL. For example, the following URL points to
+# the specification of the java.lang.String class:
+# http://java.sun.com/products/jdk/1.2/docs/api/java/lang/String.html
+#
+# This attribute's syntax is 'IA5 String' and its case is significant.
+#
+# ( 1.3.6.1.4.1.42.2.27.4.1.12
+# NAME 'javaDoc'
+# DESC 'The Java documentation for the class'
+# EQUALITY caseExactIA5Match
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+# )
+#
+attributetype ( 1.3.6.1.4.1.42.2.27.4.1.12
+ NAME 'javaDoc'
+ DESC 'The Java documentation for the class'
+ EQUALITY caseExactIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+# 4 Object Class Definitions
+#
+# The following object classes are defined in this document:
+#
+# javaContainer
+# javaObject
+# javaSerializedObject
+# javaMarshalledObject
+# javaNamingReference
+#
+# 4.1 javaContainer
+#
+# This structural object class represents a container for a Java
+# object.
+#
+# ( 1.3.6.1.4.1.42.2.27.4.2.1
+# NAME 'javaContainer'
+# DESC 'Container for a Java object'
+# SUP top
+# STRUCTURAL
+# MUST ( cn )
+# )
+#
+objectclass ( 1.3.6.1.4.1.42.2.27.4.2.1
+ NAME 'javaContainer'
+ DESC 'Container for a Java object'
+ SUP top
+ STRUCTURAL
+ MUST cn )
+
+# 4.2 javaObject
+#
+# This abstract object class represents a Java object. A javaObject
+# cannot exist in the directory; only auxiliary or structural
+# subclasses of it can exist in the directory.
+#
+# ( 1.3.6.1.4.1.42.2.27.4.2.4
+# NAME 'javaObject'
+# DESC 'Java object representation'
+# SUP top
+# ABSTRACT
+# MUST ( javaClassName )
+# MAY ( javaClassNames $
+# javaCodebase $
+# javaDoc $
+# description )
+# )
+#
+objectclass ( 1.3.6.1.4.1.42.2.27.4.2.4
+ NAME 'javaObject'
+ DESC 'Java object representation'
+ SUP top
+ ABSTRACT
+ MUST javaClassName
+ MAY ( javaClassNames $ javaCodebase $
+ javaDoc $ description ) )
+
+# 4.3 javaSerializedObject
+#
+# This auxiliary object class represents a Java serialized object. It
+# must be mixed in with a structural object class.
+#
+# ( 1.3.6.1.4.1.42.2.27.4.2.5
+# NAME 'javaSerializedObject'
+# DESC 'Java serialized object'
+# SUP javaObject
+# AUXILIARY
+# MUST ( javaSerializedData )
+# )
+#
+objectclass ( 1.3.6.1.4.1.42.2.27.4.2.5
+ NAME 'javaSerializedObject'
+ DESC 'Java serialized object'
+ SUP javaObject
+ AUXILIARY
+ MUST javaSerializedData )
+
+# 4.4 javaMarshalledObject
+#
+# This auxiliary object class represents a Java marshalled object. It
+# must be mixed in with a structural object class.
+#
+# ( 1.3.6.1.4.1.42.2.27.4.2.8
+# NAME 'javaMarshalledObject'
+# DESC 'Java marshalled object'
+# SUP javaObject
+# AUXILIARY
+# MUST ( javaSerializedData )
+# )
+#
+objectclass ( 1.3.6.1.4.1.42.2.27.4.2.8
+ NAME 'javaMarshalledObject'
+ DESC 'Java marshalled object'
+ SUP javaObject
+ AUXILIARY
+ MUST javaSerializedData )
+
+# 4.5 javaNamingReference
+#
+# This auxiliary object class represents a JNDI reference. It must be
+# mixed in with a structural object class.
+#
+# ( 1.3.6.1.4.1.42.2.27.4.2.7
+# NAME 'javaNamingReference'
+# DESC 'JNDI reference'
+# SUP javaObject
+# AUXILIARY
+# MAY ( javaReferenceAddress $
+# javaFactory )
+# )
+#
+objectclass ( 1.3.6.1.4.1.42.2.27.4.2.7
+ NAME 'javaNamingReference'
+ DESC 'JNDI reference'
+ SUP javaObject
+ AUXILIARY
+ MAY ( javaReferenceAddress $ javaFactory ) )
+
+# Full Copyright Statement
+#
+# Copyright (C) The Internet Society (1999). All Rights Reserved.
+#
+# This document and translations of it may be copied and furnished to
+# others, and derivative works that comment on or otherwise explain it
+# or assist in its implementation may be prepared, copied, published
+# and distributed, in whole or in part, without restriction of any
+# kind, provided that the above copyright notice and this paragraph are
+# included on all such copies and derivative works. However, this
+# document itself may not be modified in any way, such as by removing
+# the copyright notice or references to the Internet Society or other
+# Internet organizations, except as needed for the purpose of
+# developing Internet standards in which case the procedures for
+# copyrights defined in the Internet Standards process must be
+# followed, or as required to translate it into languages other than
+# English.
+#
+# The limited permissions granted above are perpetual and will not be
+# revoked by the Internet Society or its successors or assigns.
+#
+# This document and the information contained herein is provided on an
+# "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+# TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+# BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+# HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
Added: incubator/directory/eve/branches/start/src/schema/krb5-kdc.schema
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/schema/krb5-kdc.schema Thu Jun 24 00:06:35 2004
@@ -0,0 +1,134 @@
+# $OpenLDAP: pkg/ldap/servers/slapd/schema/krb5-kdc.schema,v 1.1.2.1 2000/09/05 18:28:34 kurt Exp $
+# $Id: krb5-kdc.schema,v 1.2 2002/12/14 01:30:10 akarasulu Exp $
+# Definitions for a Kerberos V KDC schema
+
+# OID Base is iso(1) org(3) dod(6) internet(1) private(4) enterprise(1) padl(5322) kdcSchema(10)
+#
+# Syntaxes are under 1.3.6.1.4.1.5322.10.0
+# Attributes types are under 1.3.6.1.4.1.5322.10.1
+# Object classes are under 1.3.6.1.4.1.5322.10.2
+
+# Syntax definitions
+
+#krb5KDCFlagsSyntax SYNTAX ::= {
+# WITH SYNTAX INTEGER
+#-- initial(0), -- require as-req
+#-- forwardable(1), -- may issue forwardable
+#-- proxiable(2), -- may issue proxiable
+#-- renewable(3), -- may issue renewable
+#-- postdate(4), -- may issue postdatable
+#-- server(5), -- may be server
+#-- client(6), -- may be client
+#-- invalid(7), -- entry is invalid
+#-- require-preauth(8), -- must use preauth
+#-- change-pw(9), -- change password service
+#-- require-hwauth(10), -- must use hwauth
+#-- ok-as-delegate(11), -- as in TicketFlags
+#-- user-to-user(12), -- may use user-to-user auth
+#-- immutable(13) -- may not be deleted
+# ID { 1.3.6.1.4.1.5322.10.0.1 }
+#}
+
+#krb5PrincipalNameSyntax SYNTAX ::= {
+# WITH SYNTAX OCTET STRING
+#-- String representations of distinguished names as per RFC1510
+# ID { 1.3.6.1.4.1.5322.10.0.2 }
+#}
+
+# Attribute type definitions
+
+attributetype ( 1.3.6.1.4.1.5322.10.1.1
+ NAME 'krb5PrincipalName'
+ DESC 'The unparsed Kerberos principal name'
+ EQUALITY caseExactIA5Match
+ SINGLE-VALUE
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.3.6.1.4.1.5322.10.1.2
+ NAME 'krb5KeyVersionNumber'
+ EQUALITY integerMatch
+ SINGLE-VALUE
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
+
+attributetype ( 1.3.6.1.4.1.5322.10.1.3
+ NAME 'krb5MaxLife'
+ EQUALITY integerMatch
+ SINGLE-VALUE
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
+
+attributetype ( 1.3.6.1.4.1.5322.10.1.4
+ NAME 'krb5MaxRenew'
+ EQUALITY integerMatch
+ SINGLE-VALUE
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
+
+attributetype ( 1.3.6.1.4.1.5322.10.1.5
+ NAME 'krb5KDCFlags'
+ EQUALITY integerMatch
+ SINGLE-VALUE
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
+
+attributetype ( 1.3.6.1.4.1.5322.10.1.6
+ NAME 'krb5EncryptionType'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
+
+attributetype ( 1.3.6.1.4.1.5322.10.1.7
+ NAME 'krb5ValidStart'
+ ORDERING generalizedTimeOrderingMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
+ SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.5322.10.1.8
+ NAME 'krb5ValidEnd'
+ ORDERING generalizedTimeOrderingMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
+ SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.5322.10.1.9
+ NAME 'krb5PasswordEnd'
+ ORDERING generalizedTimeOrderingMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
+ SINGLE-VALUE )
+
+# this is temporary; keys will eventually
+# be child entries or compound attributes.
+attributetype ( 1.3.6.1.4.1.5322.10.1.10
+ NAME 'krb5Key'
+ DESC 'Encoded ASN1 Key as an octet string'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 )
+
+attributetype ( 1.3.6.1.4.1.5322.10.1.11
+ NAME 'krb5PrincipalRealm'
+ DESC 'Distinguished name of krb5Realm entry'
+ SUP distinguishedName )
+
+attributetype ( 1.3.6.1.4.1.5322.10.1.12
+ NAME 'krb5RealmName'
+ EQUALITY octetStringMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.40{128} )
+
+# Object class definitions
+
+objectclass ( 1.3.6.1.4.1.5322.10.2.1
+ NAME 'krb5Principal'
+ SUP top
+ AUXILIARY
+ MUST ( krb5PrincipalName )
+ MAY ( cn $ krb5PrincipalRealm ) )
+
+objectclass ( 1.3.6.1.4.1.5322.10.2.2
+ NAME 'krb5KDCEntry'
+ SUP krb5Principal
+ AUXILIARY
+ MUST ( krb5KeyVersionNumber )
+ MAY ( krb5ValidStart $ krb5ValidEnd $ krb5PasswordEnd $
+ krb5MaxLife $ krb5MaxRenew $ krb5KDCFlags $
+ krb5EncryptionType $ krb5Key ) )
+
+objectclass ( 1.3.6.1.4.1.5322.10.2.3
+ NAME 'krb5Realm'
+ SUP top
+ AUXILIARY
+ MUST ( krb5RealmName ) )
+
Added: incubator/directory/eve/branches/start/src/schema/misc.schema
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/schema/misc.schema Thu Jun 24 00:06:35 2004
@@ -0,0 +1,66 @@
+# $OpenLDAP: pkg/ldap/servers/slapd/schema/misc.schema,v 1.2.8.11 2002/01/08 20:19:06 kurt Exp $
+#
+# Assorted definitions from several sources, including
+# ''works in progress''. Contents of this file are
+# subject to change (including deletion) without notice.
+#
+# Not recommended for production use!
+# Use with extreme caution!
+
+#
+# draft-lachman-laser-ldap-mail-routing-02.txt !!!EXPIRED!!!
+#
+attributetype ( 2.16.840.1.113730.3.1.13
+ NAME 'mailLocalAddress'
+ DESC 'RFC822 email address of this recipient'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
+
+attributetype ( 2.16.840.1.113730.3.1.18
+ NAME 'mailHost'
+ DESC 'FQDN of the SMTP/MTA of this recipient'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256}
+ SINGLE-VALUE )
+
+attributetype ( 2.16.840.1.113730.3.1.47
+ NAME 'mailRoutingAddress'
+ DESC 'RFC822 routing address of this recipient'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256}
+ SINGLE-VALUE )
+
+# OID needs to be determined
+#objectclass ( 2.16.840.1.113730.3.2.TBD
+# NAME 'inetLocalMailRecipient'
+# DESC 'Internet local mail recipient'
+# SUP top AUXILIARY
+# MAY ( mailLocalAddress $ mailHost $ mailRoutingAddress ) )
+
+# I-D leaves this OID TBD.
+# iPlanet uses 2.16.840.1.113.730.3.2.147 but that appears to be
+# an improperly delegated OID. A typo is suspected.
+objectclass ( 2.16.840.1.113730.3.2.147
+ NAME 'inetLocalMailRecipient'
+ DESC 'Internet local mail recipient'
+ SUP top AUXILIARY
+ MAY ( mailLocalAddress $ mailHost $ mailRoutingAddress ) )
+
+#
+# draft-srivastava-ldap-mail-00.txt !!!EXPIRED!!!
+#
+attributetype ( 1.3.6.1.4.1.42.2.27.2.1.15
+ NAME 'rfc822MailMember'
+ DESC 'rfc822 mail address of group member(s)'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+#
+# !!!no I-D!!!
+#
+objectclass ( 1.3.6.1.4.1.42.2.27.1.2.5
+ NAME 'nisMailAlias'
+ DESC 'NIS mail alias'
+ SUP top STRUCTURAL
+ MUST cn
+ MAY rfc822MailMember )
Added: incubator/directory/eve/branches/start/src/schema/nis.schema
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/schema/nis.schema Thu Jun 24 00:06:35 2004
@@ -0,0 +1,224 @@
+# $OpenLDAP: pkg/ldap/servers/slapd/schema/nis.schema,v 1.1.8.5 2000/09/28 17:35:12 kurt Exp $
+# Definitions from RFC2307 (Experimental)
+# An Approach for Using LDAP as a Network Information Service
+
+# Depends upon core.schema and cosine.schema
+
+# Note: The definitions in RFC2307 are given in syntaxes closely related
+# to those in RFC2252, however, some liberties are taken that are not
+# supported by RFC2252. This file has been written following RFC2252
+# strictly.
+
+# OID Base is iso(1) org(3) dod(6) internet(1) directory(1) nisSchema(1).
+# i.e. nisSchema in RFC2307 is 1.3.6.1.1.1
+#
+# Syntaxes are under 1.3.6.1.1.1.0 (two new syntaxes are defined)
+# validaters for these syntaxes are incomplete, they only
+# implement printable string validation (which is good as the
+# common use of these syntaxes violates the specification).
+# Attribute types are under 1.3.6.1.1.1.1
+# Object classes are under 1.3.6.1.1.1.2
+
+# Attribute Type Definitions
+
+attributetype ( 1.3.6.1.1.1.1.0 NAME 'uidNumber'
+ DESC 'An integer uniquely identifying a user in an administrative domain'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.1.1.1.1 NAME 'gidNumber'
+ DESC 'An integer uniquely identifying a group in an administrative domain'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.1.1.1.2 NAME 'gecos'
+ DESC 'The GECOS field; the common name'
+ EQUALITY caseIgnoreIA5Match
+ SUBSTR caseIgnoreIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.1.1.1.3 NAME 'homeDirectory'
+ DESC 'The absolute path to the home directory'
+ EQUALITY caseExactIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.1.1.1.4 NAME 'loginShell'
+ DESC 'The path to the login shell'
+ EQUALITY caseExactIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.1.1.1.5 NAME 'shadowLastChange'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.1.1.1.6 NAME 'shadowMin'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.1.1.1.7 NAME 'shadowMax'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.1.1.1.8 NAME 'shadowWarning'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.1.1.1.9 NAME 'shadowInactive'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.1.1.1.10 NAME 'shadowExpire'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.1.1.1.11 NAME 'shadowFlag'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.1.1.1.12 NAME 'memberUid'
+ EQUALITY caseExactIA5Match
+ SUBSTR caseExactIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.3.6.1.1.1.1.13 NAME 'memberNisNetgroup'
+ EQUALITY caseExactIA5Match
+ SUBSTR caseExactIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.3.6.1.1.1.1.14 NAME 'nisNetgroupTriple'
+ DESC 'Netgroup triple'
+ SYNTAX 1.3.6.1.1.1.0.0 )
+
+attributetype ( 1.3.6.1.1.1.1.15 NAME 'ipServicePort'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.1.1.1.16 NAME 'ipServiceProtocol'
+ SUP name )
+
+attributetype ( 1.3.6.1.1.1.1.17 NAME 'ipProtocolNumber'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.1.1.1.18 NAME 'oncRpcNumber'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.1.1.1.19 NAME 'ipHostNumber'
+ DESC 'IP address as a dotted decimal, eg. 192.168.1.1, omitting leading zeros'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} )
+
+attributetype ( 1.3.6.1.1.1.1.20 NAME 'ipNetworkNumber'
+ DESC 'IP network as a dotted decimal, eg. 192.168, omitting leading zeros'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.1.1.1.21 NAME 'ipNetmaskNumber'
+ DESC 'IP netmask as a dotted decimal, eg. 255.255.255.0, omitting leading zeros'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.1.1.1.22 NAME 'macAddress'
+ DESC 'MAC address in maximal, colon separated hex notation, eg. 00:00:92:90:ee:e2'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} )
+
+attributetype ( 1.3.6.1.1.1.1.23 NAME 'bootParameter'
+ DESC 'rpc.bootparamd parameter'
+ SYNTAX 1.3.6.1.1.1.0.1 )
+
+attributetype ( 1.3.6.1.1.1.1.24 NAME 'bootFile'
+ DESC 'Boot image name'
+ EQUALITY caseExactIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.3.6.1.1.1.1.26 NAME 'nisMapName'
+ SUP name )
+
+attributetype ( 1.3.6.1.1.1.1.27 NAME 'nisMapEntry'
+ EQUALITY caseExactIA5Match
+ SUBSTR caseExactIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{1024} SINGLE-VALUE )
+
+# Object Class Definitions
+
+objectclass ( 1.3.6.1.1.1.2.0 NAME 'posixAccount' SUP top AUXILIARY
+ DESC 'Abstraction of an account with POSIX attributes'
+ MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory )
+ MAY ( userPassword $ loginShell $ gecos $ description ) )
+
+objectclass ( 1.3.6.1.1.1.2.1 NAME 'shadowAccount' SUP top AUXILIARY
+ DESC 'Additional attributes for shadow passwords'
+ MUST uid
+ MAY ( userPassword $ shadowLastChange $ shadowMin $
+ shadowMax $ shadowWarning $ shadowInactive $
+ shadowExpire $ shadowFlag $ description ) )
+
+objectclass ( 1.3.6.1.1.1.2.2 NAME 'posixGroup' SUP top STRUCTURAL
+ DESC 'Abstraction of a group of accounts'
+ MUST ( cn $ gidNumber )
+ MAY ( userPassword $ memberUid $ description ) )
+
+objectclass ( 1.3.6.1.1.1.2.3 NAME 'ipService' SUP top STRUCTURAL
+ DESC 'Abstraction an Internet Protocol service.
+ Maps an IP port and protocol (such as tcp or udp)
+ to one or more names; the distinguished value of
+ the cn attribute denotes the service"s canonical
+ name'
+ MUST ( cn $ ipServicePort $ ipServiceProtocol )
+ MAY ( description ) )
+
+objectclass ( 1.3.6.1.1.1.2.4 NAME 'ipProtocol' SUP top STRUCTURAL
+ DESC 'Abstraction of an IP protocol. Maps a protocol number
+ to one or more names. The distinguished value of the cn
+ attribute denotes the protocol"s canonical name'
+ MUST ( cn $ ipProtocolNumber $ description )
+ MAY description )
+
+objectclass ( 1.3.6.1.1.1.2.5 NAME 'oncRpc' SUP top STRUCTURAL
+ DESC 'Abstraction of an Open Network Computing (ONC)
+ [RFC1057] Remote Procedure Call (RPC) binding.
+ This class maps an ONC RPC number to a name.
+ The distinguished value of the cn attribute denotes
+ the RPC service"s canonical name'
+ MUST ( cn $ oncRpcNumber $ description )
+ MAY description )
+
+objectclass ( 1.3.6.1.1.1.2.6 NAME 'ipHost' SUP top AUXILIARY
+ DESC 'Abstraction of a host, an IP device. The distinguished
+ value of the cn attribute denotes the host"s canonical
+ name. Device SHOULD be used as a structural class'
+ MUST ( cn $ ipHostNumber )
+ MAY ( l $ description $ manager ) )
+
+objectclass ( 1.3.6.1.1.1.2.7 NAME 'ipNetwork' SUP top STRUCTURAL
+ DESC 'Abstraction of a network. The distinguished value of
+ the cn attribute denotes the network"s canonical name'
+ MUST ( cn $ ipNetworkNumber )
+ MAY ( ipNetmaskNumber $ l $ description $ manager ) )
+
+objectclass ( 1.3.6.1.1.1.2.8 NAME 'nisNetgroup' SUP top STRUCTURAL
+ DESC 'Abstraction of a netgroup. May refer to other netgroups'
+ MUST cn
+ MAY ( nisNetgroupTriple $ memberNisNetgroup $ description ) )
+
+objectclass ( 1.3.6.1.1.1.2.9 NAME 'nisMap' SUP top STRUCTURAL
+ DESC 'A generic abstraction of a NIS map'
+ MUST nisMapName
+ MAY description )
+
+objectclass ( 1.3.6.1.1.1.2.10 NAME 'nisObject' SUP top STRUCTURAL
+ DESC 'An entry in a NIS map'
+ MUST ( cn $ nisMapEntry $ nisMapName )
+ MAY description )
+
+objectclass ( 1.3.6.1.1.1.2.11 NAME 'ieee802Device' SUP top AUXILIARY
+ DESC 'A device with a MAC address; device SHOULD be
+ used as a structural class'
+ MAY macAddress )
+
+objectclass ( 1.3.6.1.1.1.2.12 NAME 'bootableDevice' SUP top AUXILIARY
+ DESC 'A device with boot parameters; device SHOULD be
+ used as a structural class'
+ MAY ( bootFile $ bootParameter ) )
Added: incubator/directory/eve/branches/start/src/schema/openldap.schema
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/schema/openldap.schema Thu Jun 24 00:06:35 2004
@@ -0,0 +1,31 @@
+# $OpenLDAP: pkg/ldap/servers/slapd/schema/openldap.schema,v 1.10.2.6 2000/10/11 02:36:50 kurt Exp $
+#
+# OpenLDAP Project's directory schema items
+#
+# depends upon:
+# core.schema
+# cosine.schema
+# inetorgperson.schema
+#
+# These are provided for informational purposes only.
+
+objectclass ( 1.3.6.1.4.1.4203.1.4.3 NAME 'OpenLDAPorg'
+ DESC 'OpenLDAP Organizational Object'
+ SUP organization
+ MAY ( buildingName $ displayName $ labeledURI ) )
+
+objectclass ( 1.3.6.1.4.1.4203.1.4.4 NAME 'OpenLDAPou'
+ DESC 'OpenLDAP Organizational Unit Object'
+ SUP organizationalUnit
+ MAY ( buildingName $ displayName $ labeledURI $ o ) )
+
+objectclass ( 1.3.6.1.4.1.4203.1.4.5 NAME 'OpenLDAPperson'
+ DESC 'OpenLDAP Person'
+ SUP ( pilotPerson $ inetOrgPerson )
+ MUST ( uid $ cn )
+ MAY ( givenName $ labeledURI $ o ) )
+
+objectclass ( 1.3.6.1.4.1.4203.1.4.6 NAME 'OpenLDAPdisplayableObject'
+ DESC 'OpenLDAP Displayable Object'
+ MAY displayName AUXILIARY )
+
Added: incubator/directory/eve/branches/start/src/schema/our.schema
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/schema/our.schema Thu Jun 24 00:06:35 2004
@@ -0,0 +1,27 @@
+#
+# Internal operational attributes used by our server. We do not have valid OIDs
+# for these datatypes so we made them up. This really is a bad idea. But its
+# a temp fix.
+#
+
+attributetype ( 2.5.18.12.5.18.12.5.18.1 NAME 'parentId'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+ SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )
+
+attributetype ( 2.5.18.12.5.18.12.5.18.2 NAME 'entryId'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+ SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )
+
+attributetype ( 2.5.18.12.5.18.12.5.18.3 NAME 'numSubordinates'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+ SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )
+
+attributetype ( 2.5.18.12.5.18.12.5.18.4 NAME 'parentDn'
+ EQUALITY distinguishedNameMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
+ SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )
+
+
Added: incubator/directory/eve/branches/start/src/schema/vendor.schema
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/src/schema/vendor.schema Thu Jun 24 00:06:35 2004
@@ -0,0 +1,41 @@
+#
+# Storing Vendor Information in the LDAP root DSE
+# http://www.faqs.org/rfcs/rfc3045.html
+#
+
+
+
+# 2.1 vendorName
+#
+# This attribute contains a single string, which represents the name of
+# the LDAP server implementer.
+#
+# All LDAP server implementations SHOULD maintain a vendorName, which
+# is generally the name of the company that wrote the LDAP Server code
+# like "Novell, Inc."
+
+attributetype ( 1.3.6.1.1.4 NAME 'vendorName'
+ EQUALITY caseExactIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+ SINGLE-VALUE NO-USER-MODIFICATION USAGE dSAOperation )
+
+
+# 2.2 vendorVersion
+# This attribute contains a string which represents the version of the
+# LDAP server implementation.
+#
+# All LDAP server implementations SHOULD maintain a vendorVersion.
+# Note that this value is typically a release value--comprised of a
+# string and/or a string of numbers--used by the developer of the LDAP
+# server product (as opposed to the supportedLDAPVersion, which
+# specifies the version of the LDAP protocol supported by this server).
+# This is single-valued so that it will only have one version value.
+# This string MUST be unique between two versions, but there are no
+# other syntactic restrictions on the value or the way it is formatted.
+
+attributetype ( 1.3.6.1.1.5 NAME 'vendorVersion'
+ EQUALITY caseExactIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+ SINGLE-VALUE NO-USER-MODIFICATION USAGE dSAOperation )
+
+
Added: incubator/directory/eve/branches/start/todo.txt
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/todo.txt Thu Jun 24 00:06:35 2004
@@ -0,0 +1,4 @@
+ o add check to build.xml for proper ant version
+ o test it out
+ o add modified phoenix download and install option to build
+
Added: incubator/directory/eve/branches/start/xdocs/design/operations/index.xml
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/xdocs/design/operations/index.xml Thu Jun 24 00:06:35 2004
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+<document>
+ <body>
+ <section name="LDAP Operations">
+ <p>Currently no content for this page.</p>
+ </section>
+ </body>
+</document>
Added: incubator/directory/eve/branches/start/xdocs/design/operations/navigation.xml
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/xdocs/design/operations/navigation.xml Thu Jun 24 00:06:35 2004
@@ -0,0 +1,44 @@
+<?xml version="1.0"?>
+<project name="LDAPd">
+ <title>Home</title>
+ <body>
+ <links>
+ <item name="LDAPd" href="http://ldapd.sourceforge.net"/>
+ </links>
+ <menu name="Overview">
+ <item name="Home" href="http://ldapd.sourceforge.net"/>
+ </menu>
+ <menu name="Design Documentation">
+ <item name="Authentication" href="/authentication-module.html"/>
+ <item name="Backend" href="/../../backend-module.html"/>
+ <item name="Client" href="/../../client-module.html"/>
+ <item name="Decoder" href="/../../decoder-module.html"/>
+ <item name="Encoder" href="/../../encoder-module.html"/>
+ <item name="Event" href="/../../event-module.html"/>
+ <item name="Input" href="/../../input-module.html"/>
+ <item name="JNDI Provider" href="/../../jndi-provider-module.html"/>
+ <item name="Listener" href="/../../listener-module.html"/>
+ <item name="Nexus" href="/../../nexus-module.html"/>
+ <item name="Output" href="/../../output-module.html"/>
+ <item name="Protocol" href="/../../protocol-module.html"/>
+ <item name="RootDSE" href="/../../rootdse-/design.html"/>
+ <item name="Schema" href="/../../schema-module.html"/>
+ <item name="SEDA" href="/../../seda-implementation.html"/>
+ <item name="Server Architecture" href="/../../server-architecture.html"/>
+ <item name="Triggers and Procedures" href="/../../triggers-and-procedures.html"/>
+ <item/>
+ <item name="Operations" href="/design/operations/index.html">
+ <item name="Search" href="/design/operations/search-operation.html"/>
+ </item>
+ </menu>
+ <menu name="Other Modules">
+ <item name="Common" href="/../../../module-blank.html"/>
+ <item name="Replication" href="/../../../module-blank.html"/>
+ </menu>
+ <menu name="Backends">
+ <item name="Berkeley" href="/../../../backend-blank.html"/>
+ <item name="JDBC" href="/../../../backend-blank.html"/>
+ <item name="JDBM" href="/../../../backend-blank.html"/>
+ </menu>
+ </body>
+</project>
Added: incubator/directory/eve/branches/start/xdocs/devprocess.xml
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/xdocs/devprocess.xml Thu Jun 24 00:06:35 2004
@@ -0,0 +1,3 @@
+<?xml version="1.0"?>
+<document>
+</document>
Added: incubator/directory/eve/branches/start/xdocs/index.xml
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/xdocs/index.xml Thu Jun 24 00:06:35 2004
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<document>
+ <properties>
+ <author email="bearcej at users.sourceforge.net">Jim Bearce</author>
+ <title>LDAPd</title>
+ </properties>
+ <body>
+ <section name="Server Documentation">
+ <p>This subproject consists of the core server code which makes up the heart
+ of the LDAPd project.</p>
+ <p>The parts of the server are documented in the following pages.</p>
+ </section>
+ </body>
+</document>
Added: incubator/directory/eve/branches/start/xdocs/navigation.xml
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/xdocs/navigation.xml Thu Jun 24 00:06:35 2004
@@ -0,0 +1,42 @@
+<?xml version="1.0"?>
+<project name="LDAPd">
+ <title>Home</title>
+ <body>
+ <links>
+ <item name="Avalon" href="http://avalon.apache.org"/>
+ <item name="Phoenix" href="http://avalon.apache.org/phoenix"/>
+ </links>
+ <menu name="Overview">
+ <item name="Home" href="/../../"/>
+ </menu>
+ <menu name="Design Documentation">
+ <item name="Authentication" href="/design/authentication-module.html"/>
+ <item name="Backend" href="/design/backend-module.html"/>
+ <item name="Client" href="/design/client-module.html"/>
+ <item name="Decoder" href="/design/decoder-module.html"/>
+ <item name="Encoder" href="/design/encoder-module.html"/>
+ <item name="Event" href="/design/event-module.html"/>
+ <item name="Input" href="/design/input-module.html"/>
+ <item name="JNDI Provider" href="/design/jndi-provider-module.html"/>
+ <item name="Listener" href="/design/listener-module.html"/>
+ <item name="Nexus" href="/design/nexus-module.html"/>
+ <item name="Output" href="/design/output-module.html"/>
+ <item name="Protocol" href="/design/protocol-module.html"/>
+ <item name="RootDSE" href="/design/rootdse-design.html"/>
+ <item name="Schema" href="/design/schema-module.html"/>
+ <item name="SEDA" href="/design/seda-implementation.html"/>
+ <item name="Server Architecture" href="/design/server-architecture.html"/>
+ <item name="Triggers and Procedures" href="/design/triggers-and-procedures.html"/>
+ <item/>
+ <item name="Operations" href="/design/operations/index.html"/>
+ </menu>
+ <menu name="LDAPd Subprojects">
+ <item name="Berkeley" href="/../../backend-blank.html"/>
+ <item name="Common" href="/../../modules/ldapd-common"/>
+ <item name="JDBC" href="/../../modules/ldapd-modjdbc"/>
+ <item name="JDBM" href="/../../modules/ldapd-modjdbm"/>
+ <item name="Replication" href="/../../module-blank.html"/>
+ <item name="SNACC Provider" href="/../../modules/ldapd-snacc-provider"/>
+ </menu>
+ </body>
+</project>
Added: incubator/directory/eve/branches/start/xdocs/stylesheets/tigris.css
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/xdocs/stylesheets/tigris.css Thu Jun 24 00:06:35 2004
@@ -0,0 +1,427 @@
+/* contains rules unsuitable for Netscape 4.x; simpler rules are in ns4_only.css. see <http://style.tigris.org/> */
+
+/* colors, backgrounds, borders, link indication */
+
+body {
+ background: #fff;
+ color: #000;
+ }
+.app h3, .app h4, .app th, .tabs td, .tabs th, .functnbar {
+ }
+#navcolumn div div.heading {
+ background-image: none;
+ }
+.app h3, .app h4 {
+ color: #fff;
+ }
+.app h3 {
+ background-color: #036;
+ }
+.app h4 {
+ background-color: #eee;
+ }
+.a td {
+ background: #ddd;
+ }
+.b td {
+ background: #efefef;
+ }
+table, th, td {
+ border: none
+ }
+.mtb {
+ border-top: solid 1px #ddd;
+ }
+div.colbar {
+ background: #bbb;
+ }
+div#banner {
+ border-top: 1px solid #369;
+ border-bottom: 1px solid #003;
+ }
+div#helptext th {
+ border-bottom: 1px solid #996;
+ border-right: 1px solid #996;
+ }
+div#helptext td {
+ border-bottom: 1px solid #cc9;
+ border-right: 1px solid #cc9;
+ }
+.tabs {
+ border-bottom: .75em #888 solid;
+ }
+.tabs th, .tabs td {
+ border-right: 1px solid #333;
+ }
+.tabs td {
+ border-bottom: 1px solid #ddd;
+ }
+#navcolumn {
+ background: #eee;
+ border-right: 1px solid #aaa;
+ border-bottom: 1px solid #aaa;
+ }
+#breadcrumbs {
+ border-bottom: 1px solid #aaa;
+ background-color: #ddd;
+ }
+#navcolumn, #breadcrumbs {
+ border-top: 1px solid #fff;
+ }
+#rightcol div.www, #rightcol div.help {
+ border: 1px solid #ddd;
+ }
+div#navcolumn div.focus {
+ border-top: 1px solid #aaa;
+ border-left: 1px solid #aaa;
+ background-color: #fff;
+ }
+body.docs div.docs {
+ background: #fff;
+ border-left: 1px solid #ddd;
+ border-top: 1px solid #ddd;
+ }
+body.docs {
+ background: #eee url(../images/help_logo.gif) top right no-repeat !important;
+ }
+.docs h3, .docs h4 {
+ border-top: solid 1px #000;
+ }
+#alerterrormessage {
+ background: url(../images/icon_alert.gif) top left no-repeat !important;
+ }
+.functnbar {
+ background-color: #aaa;
+ }
+.functnbar2, .functnbar3 {
+ background: #aaa url(../images/sw_min.gif) no-repeat bottom left;
+ }
+.functnbar3 {
+ background-color: #ddd;
+ }
+.functnbar, .functnbar2, .functnbar3 {
+ color: #000;
+ }
+.functnbar a, .functnbar2 a, .functnbar3 a {
+ color: #000;
+ text-decoration: underline;
+ }
+#topmodule {
+ background: #ddd;
+ border-top: 1px solid #fff;
+ border-bottom: 1px solid #aaa;
+ border-right: 1px solid #aaa;
+ }
+#topmodule #issueid {
+ border-right: 1px solid #aaa;
+ }
+a:link, #navcolumn a:visited, .app a:visited, .tasknav a:visited {
+ color: blue;
+ }
+a:active, a:hover, #leftcol a:active, #leftcol a:hover {
+ color: #f30 !important;
+ }
+#login a:link, #login a:visited {
+ color: white;
+ text-decoration: underline;
+ }
+#banner a:active, #banner a:hover {
+ color: #f90 !important;
+ }
+#leftcol a, #breadcrumbs a {
+ text-decoration: none;
+ }
+a:link.selfref, a:visited.selfref {
+ color: #555 !important;
+ text-decoration: none;
+ }
+h2 .lastchild {
+ color: #777
+ }
+.tabs td, .tabs th {
+ background-color: #ddd;
+ }
+.app th {
+ background-color: #bbb;
+ }
+.tabs th {
+ background-color: #888;
+ color: #fff;
+ }
+.axial th {
+ background-color: #ddd;
+ color: black
+ }
+.tabs td {
+ background-color: #ddd;
+ }
+.alert {
+ color: #c00;
+ }
+.confirm {
+ color: green;
+ }
+.info {
+ color: blue;
+ }
+.selection {
+ background: #ffc;
+ }
+#login {
+ color: #fff;
+ }
+#helptext th {
+ background: #cc9;
+ }
+#helptext td {
+ background: #ffc;
+ }
+.tabs a {
+ text-decoration: none;
+ }
+#navcolumn div strong {
+ color: #000;
+ }
+#banner, #banner td {
+ background: #036;
+ color: #fff;
+ }
+body #banner #login a {
+ color: #fff;
+ }
+
+
+/* font and text properties, exclusive of link indication, alignment, text-indent */
+
+body, th, td, input, select, textarea, h2 small {
+ font-family: Verdana, Helvetica, Arial, sans-serif;
+ }
+code, pre {
+ font-family: 'Andale Mono', Courier, monospace;
+ }
+html body, body th, body td, textarea, h2 small, .app h3, .app h4, #rightcol h3, #bodycol pre, #bodycol code {
+ font-size: x-small;
+ voice-family: "\"}\"";
+ voice-family: inherit;
+ font-size: small
+ }
+html>body, html>body th, html>body td, html>body input, html>body select, html>body textarea, html>body h2 small, html>body .app h3, html>body .app h4, html>body #rightcol h3, html>body #bodycol pre, html>body #bodycol code {
+ font-size: small
+ }
+small, div#footer td, div#login, div#helptext th, div#helptext td, div.tabs th, div.tabs td, input, select, .paginate, .functnbar, .functnbar2, .functnbar3, #breadcrumbs td, .courtesylinks, #rightcol div.help, .colbar, .tasknav, body.docs div#toc {
+ font-size: xx-small;
+ voice-family: "\"}\"";
+ voice-family: inherit;
+ font-size: x-small
+ }
+html>body small, html>body div#footer td, html>body div#login, html>body div#helptext td, html>body div#helptext th, html>body div.tabs th, html>body div.tabs td, html>body input, html>body select, html>body .paginate, html>body .functnbar, html>body .functnbar2, html>body .functnbar3, html>body #breadcrumbs td, html>body .courtesylinks, html>body #rightcol div.help, html>body .colbar, html>body .tasknav, html>body.docs #toc {
+ font-size: x-small
+ }
+#bodycol h2 {
+ font-family: Tahoma, Verdana, Helvetica, Arial, sans-serif;
+ font-size: 1.5em;
+ font-weight: normal;
+ }
+h2 small {
+ font-weight: bold;
+ letter-spacing: .06em;
+ }
+dt {
+ font-weight: bold
+ }
+#login .username {
+ font-weight: bold;
+ }
+h4 {
+ font-size: 1em;
+ }
+#breadcrumbs td {
+ font-weight: bold;
+ }
+.selection {
+ font-weight: bold
+ }
+
+
+/* box properties (exclusive of borders), positioning, alignments, list types, text-indent */
+
+#bodycol h2 {
+ margin-top: .3em;
+ margin-bottom: .5em;
+ }
+p, ul, ol, dl {
+ margin-top: .67em;
+ margin-bottom: .67em;
+ }
+h3, h4 {
+ margin-bottom: 0;
+ }
+form {
+ margin-top: 0;
+ margin-bottom: 0;
+ }
+#bodycol {
+ padding-left: 12px;
+ padding-right: 12px;
+ width: 100%;
+ voice-family: "\"}\"";
+ voice-family: inherit;
+ width: auto;
+ }
+html>body #bodycol {
+ width: auto;
+ }
+.docs {
+ line-height: 1.4;
+ }
+.app h3, .app h4 {
+ padding: 5px;
+ margin-right: 2px;
+ margin-left: 2px;
+ }
+.h3 p, .h4 p, .h3 dt, .h4 dt {
+ margin-right: 7px;
+ margin-left: 7px;
+ }
+.tasknav {
+ margin-bottom: 1.33em
+ }
+div.colbar {
+ padding: 4px;
+ margin: 2px 2px 0;
+ }
+.tabs {
+ margin-top: .67em;
+ margin-right: 2px;
+ margin-left: 2px;
+ }
+#leftcol {
+ padding-bottom: .5em;
+ }
+#breadcrumbs td {
+ vertical-align: middle;
+ padding: 2px 8px;
+ }
+#rightcol div.www, #rightcol div.help {
+ padding: 0 .5em
+ }
+#navcolumn {
+ margin: -8px -8px 0 -8px;
+ padding: 4px;
+ }
+#navcolumn div {
+ padding-left: 5px
+ }
+div#navcolumn div div {
+ margin-top: .3em;
+ margin-bottom: .3em;
+ }
+div#navcolumn div.focus {
+ margin-top: -.1em;
+ padding: .2em 4px;
+ }
+body.docs #toc {
+ position: absolute;
+ top: 15px;
+ left: 0px;
+ width: 120px;
+ padding: 0 20px 0 0
+ }
+body.docs #toc ul, #toc ol {
+ margin-left: 0;
+ padding-left: 0;
+ }
+body.docs #toc li {
+ margin-top: 7px;
+ padding-left: 10px;
+ list-style-type: none;
+ }
+body.docs div.docs {
+ margin: 61px 0 0 150px;
+ padding: 1em 2em 1em 1em !important;
+ }
+.docs p+p {
+ text-indent: 5%;
+ margin-top: -.67em
+ }
+.docs h3, .docs h4 {
+ margin-bottom: .1em;
+ padding-top: .3em;
+ }
+#alerterrormessage {
+ padding-left: 100px;
+ }
+.functnbar, .functnbar2, .functnbar3 {
+ padding: 5px;
+ margin: .67em 2px;
+ }
+#topmodule td {
+ vertical-align: middle;
+ padding: 2px 8px
+ }
+body {
+ padding: 1em;
+ }
+body.composite, body.docs {
+ margin: 0;
+ padding: 0;
+ }
+th, td {
+ text-align: left;
+ vertical-align: top
+ }
+.right {
+ text-align: right !important;
+ }
+.center {
+ text-align: center !important;
+ }
+.tabs td, .tabs th {
+ padding-left: 7px;
+ padding-right: 7px;
+ }
+.axial th {
+ text-align: right;
+ }
+.app .axial td th {
+ text-align: left;
+ }
+body td .stb {
+ margin-top: 1em;
+ text-indent: 0;
+ }
+body td .mtb {
+ margin-top: 2em;
+ text-indent: 0;
+ }
+dd {
+ margin-bottom: .67em;
+ }
+#footer {
+ margin: 4px
+ }
+#helptext {
+ margin-top: 1em
+ }
+#helptext td div {
+ margin: .5em
+ }
+.courtesylinks {
+ margin-top: 1em;
+ padding-top: 1em
+ }
+#navcolumn div {
+ margin-bottom: .5em;
+ }
+#navcolumn div div {
+ margin-top: .3em
+ }
+#navcolumn div div {
+ padding-left: 1em;
+ }
+#banner, #banner td {
+ vertical-align: middle;
+ }
+body.docs, body.nonav {
+ margin: 1em
+ }
Added: incubator/directory/eve/branches/start/xdocs/temp.xml
==============================================================================
--- (empty file)
+++ incubator/directory/eve/branches/start/xdocs/temp.xml Thu Jun 24 00:06:35 2004
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<document>
+ <properties>
+ <author email="bearcej at users.sourceforge.net">Jim Bearce</author>
+ <title>LDAPd Documentation Place Holder</title>
+ </properties>
+</document>